package com.example.score.service;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.score.entity.KnowledgeScoreInfo;
import com.example.score.dto.*;
import com.example.score.entity.*;
import com.example.score.entity.vo.AcademicLevelResult;
import com.example.score.entity.vo.ExamSubmitRateVo;
import com.example.score.entity.vo.KnowledgeMap;
import com.example.score.entity.vo.SubObjScore;
import com.example.score.mapper.*;
import com.example.score.utils.CalculateQuestionNumUtil;
import com.example.score.utils.ExcelGenerator;
import com.example.score.utils.HttpUtils;
import com.example.score.utils.constants.ScoreFiveRateConstants;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.Collator;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class ScoreAnalysisService {

    public final ScoreStatisticsMapper scoreStatisticsMapper;
    public final ScoreDetailMapper scoreDetailMapper;
    public final ScoreDetailQuestionMapper scoreDetailQuestionMapper;
    public final SubmitStatisticsMapper submitStatisticsMapper;
    public final ExamDetailMapper examDetailMapper;
    public final StudentSubmitMapper studentSubmitMapper;
    public final QuestionScoreMapper questionScoreMapper;
    public final ClassInfoMapper classInfoMapper;
    public final QuestionInfoMapper questionInfoMapper;
    private final ExamBaseMapper examBaseMapper;
    private final GradeInfoMapper gradeInfoMapper;

    @Value("${api.base-tk-url}")
    private String baseUrl;

    @Value("${api.base-yj-url}")
    private String yjUrl;

    private final ScoreMapper scoreMapper;
    
    @Value("${bsta.profile}")
    private String excelPath;

    public Map<String, Object> calculateScoreOverview(Long examId, Long classId) {
        try {
            // 获取考试详情
            ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
            if (examDetail == null) {
                throw new RuntimeException("未找到考试详情");
            }

            Map<String, Object> classData = new HashMap<>();

            // 获取班级信息和提交记录
            List<ClassInfo> classInfos = classInfoMapper.selectByExamDetailId(examDetail.getId());

            ClassInfo classInfo = classInfos.stream().filter(ci -> ci.getClassId().equals(classId)).findFirst().orElse(null);
            if (classInfo == null) {
                throw new RuntimeException("未找到班级信息");
            }

            // 获取该班级的所有学生提交记录
            List<StudentSubmit> examSubmits = studentSubmitMapper.selectByExamDetailId(examDetail.getId())
                    .stream()
                    .filter(s -> s.getSubmitStatus() == 1)  // 只统计有效提交
                    .collect(Collectors.toList());
            List<StudentSubmit> submits = examSubmits.stream().filter(e -> e.getClassInfoId().equals(classInfo.getId())).collect(Collectors.toList());
            // 计算基础数据
            int totalCount = classInfo.getStudentCount(); // 班级总人数
            int submitCount = submits.size();  // 有效提交人数

            classData.put("totalCount", totalCount);
            classData.put("submitCount", submitCount);

            // 获取未提交学生名单
            List<String> unsubmittedList = studentSubmitMapper.findUnsubmittedStudents(classInfo.getClassId(), examDetail.getId());
            classData.put("unsubmittedList", unsubmittedList);
            classData.put("fullScore", examDetail.getFullScore());  // 添加满分
            //计算年级统计数据
            if(!examSubmits.isEmpty()) {
                classData.put("examHighestScore", CommonUtils.calculateMaxScore(examSubmits));
                classData.put("examAvgScore", CommonUtils.calculateAverageScore(examSubmits));
                classData.put("examExcellentPercent", CommonUtils.calculateExcellentRate(examSubmits, examDetail.getFullScore()));
                classData.put("examPassPercent", CommonUtils.calculatePassRate(examSubmits, examDetail.getFullScore()));
                classData.put("examMedianScore", CommonUtils.calculateMedianScore(examSubmits));
                classData.put("examMinScore", CommonUtils.calculateMinScore(examSubmits));
                classData.put("examStdDeviation", CommonUtils.calculateStandardDeviationForSubmits(examSubmits));
            }else {
                classData.put("examHighestScore", 0.00);
                classData.put("examAvgScore", 0.00);
                classData.put("examExcellentPercent", 0.00);
                classData.put("examPassPercent", 0.00);
                classData.put("examMedianScore", 0.00);
                classData.put("examStdDeviation", 0.00);
            }
            // 计算班级统计数据
            if (!submits.isEmpty()) {
                classData.put("highestScore", CommonUtils.calculateMaxScore(submits));
                classData.put("avgScore", CommonUtils.calculateAverageScore(submits));
                classData.put("excellentPercent", CommonUtils.calculateExcellentRate(submits, examDetail.getFullScore()));
                classData.put("passPercent", CommonUtils.calculatePassRate(submits, examDetail.getFullScore()));
                classData.put("medianScore", CommonUtils.calculateMedianScore(submits));
                classData.put("minScore", CommonUtils.calculateMinScore(submits));
                classData.put("stdDeviation", CommonUtils.calculateStandardDeviationForSubmits(submits));
            } else {
                classData.put("highestScore", 0.00);
                classData.put("avgScore", 0.00);
                classData.put("excellentPercent", 0.00);
                classData.put("passPercent", 0.00);
                classData.put("medianScore", 0.00);
                classData.put("stdDeviation", 0.00);
            }
            return classData;

        } catch (Exception e) {
            log.error("计算成绩概览失败: {}", e.getMessage(), e);
            throw new RuntimeException("计算成绩概览失败: " + e.getMessage());
        }
    }

    public List<Map<String, Object>> calculateGradeScoreOverview(Long examId, List<Long> classIds) {
        try {
            // 获取考试详情
            ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
            if (examDetail == null) {
                throw new RuntimeException("未找到考试详情");
            }
            List<Map<String, Object>> result = new ArrayList<>();
            // 获取班级信息和提交记录
            // 获取该班级的所有学生提交记录
            List<StudentSubmit> examSubmits = studentSubmitMapper.selectByExamDetailId(examDetail.getId())
                    .stream()
                    .filter(s -> s.getSubmitStatus() == 1)  // 只统计有效提交
                    .collect(Collectors.toList());
            if(ObjectUtils.isEmpty(classIds)){
                classIds = examSubmits.stream().map(s -> s.getClassId()).collect(Collectors.toList());
            }else {
                List<Long> finalClassIds = classIds;
                examSubmits = examSubmits.stream().filter(e -> finalClassIds.contains(e.getClassId())).collect(Collectors.toList());
            }
            if(examSubmits.isEmpty()) {
                throw new RuntimeException("未找到提交试卷/作业信息");
            }
            List<ClassInfo> classInfos = classInfoMapper.selectByClassIds(classIds);
            //先计算全体的
            AcademicLevelResult academicLevelResult = getFiveRates(examDetail.getSubjectOnlyid(), examDetail.getGradeId());
            double fullScore = examDetail.getFullScore().doubleValue();
            List<FiveRate> fiveRates = getExamFiveRates(academicLevelResult, fullScore);
            //计算年级统计数据
            Map<String, Object> gradeData = new HashMap<>();
            if(!examSubmits.isEmpty()) {
                gradeData.put("highestScore", CommonUtils.calculateMaxScore(examSubmits));
                gradeData.put("AvgScore", String.format("%.2f", CommonUtils.calculateAverageScore(examSubmits)));
                gradeData.put("excellentPercent", CommonUtils.countExcellent(examSubmits, fiveRates));
                gradeData.put("passPercent", CommonUtils.countPass(examSubmits, fiveRates));
                gradeData.put("medianScore", CommonUtils.calculateMedianScore(examSubmits));
                gradeData.put("stdDeviation", CommonUtils.calculateStandardDeviationForSubmits(examSubmits));
                gradeData.put("name", "全体");
                gradeData.put("type", 0);
            }else {
                gradeData.put("highestScore", 0.00);
                gradeData.put("avgScore", 0.00);
                gradeData.put("excellentPercent", 0.00);
                gradeData.put("passPercent", 0.00);
                gradeData.put("medianScore", 0.00);
                gradeData.put("stdDeviation", 0.00);
                gradeData.put("name", "全体");
                gradeData.put("type", 0);
            }
            result.add(gradeData);
            Map<Long,List<StudentSubmit>> classMaps = examSubmits.stream().collect(Collectors.groupingBy(StudentSubmit::getClassId));
            classMaps.forEach((k, v) ->{
                if(v.isEmpty()){
                    return;
                }
                Map<String, Object> classData = new HashMap<>();
                Optional<ClassInfo> optionalValue = classInfos.stream().filter(c-> c.getClassId().equals(k)).findFirst();
                ClassInfo classInfo = optionalValue.get();
                classData.put("name", classInfo.getClassName());
                // 计算班级的数据
                int totalCount = classInfo.getStudentCount(); // 班级总人数
                int submitCount = v.size();  // 有效提交人数
                classData.put("totalCount", totalCount);
                classData.put("submitCount", submitCount);
                // 获取未提交学生名单
                List<String> unsubmittedList = studentSubmitMapper.findUnsubmittedStudents(classInfo.getClassId(), examDetail.getId());
                classData.put("unsubmittedList", unsubmittedList);
                classData.put("fullScore", examDetail.getFullScore());  // 添加满分
                classData.put("type", 1);
                // 计算班级统计数据
                if (!v.isEmpty()) {
                    classData.put("highestScore", CommonUtils.calculateMaxScore(v));
                    classData.put("avgScore", String.format("%.2f", CommonUtils.calculateAverageScore(v)));
                    classData.put("excellentPercent", CommonUtils.countExcellent(v, fiveRates));
                    classData.put("passPercent", CommonUtils.countPass(v, fiveRates));
                    classData.put("medianScore", CommonUtils.calculateMedianScore(v));
                    classData.put("stdDeviation", CommonUtils.calculateStandardDeviationForSubmits(v));
                } else {
                    classData.put("highestScore", 0.00);
                    classData.put("avgScore", 0.00);
                    classData.put("excellentPercent", 0.00);
                    classData.put("passPercent", 0.00);
                    classData.put("medianScore", 0.00);
                    classData.put("stdDeviation", 0.00);
                }
                result.add(classData);
            });
            return result;

        } catch (Exception e) {
            log.error("计算成绩概览失败: {}", e.getMessage(), e);
            throw new RuntimeException("计算成绩概览失败: " + e.getMessage());
        }
    }

    /**
     * 作业得分表
     *
     * @param examId
     * @param classId
     * @return
     */
    public List<Map<String, Object>> calculateScoreDetails(Long examId, Long classId) {
        try {
            List<Map<String, Object>> result = new ArrayList<>();
            ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
            if(examDetail == null) {
                throw new RuntimeException("未找到考试信息");
            }
            // 获取学生提交记录
            ClassInfo classInfo = classInfoMapper.selectByClassId(classId, examDetail.getId());
            if(classInfo == null){
                throw new Exception("未找到班级，班级id：" + classId);
            }
            List<StudentSubmit> submits = studentSubmitMapper.selectListByExamDetailId(examDetail.getId());
            //按照
            if(submits.isEmpty()){
                return result;
            }
            List<QuestionInfo> questionInfos = questionInfoMapper.selectByExamDetailId(examDetail.getId());
            // 过滤有效提交
            submits = submits.stream()
                    .filter(s -> s.getSubmitStatus() == 1)
                    .collect(Collectors.toList());
            List<Long> submitIds = submits.stream().map(StudentSubmit::getId).collect(Collectors.toList());
            List<QuestionScore> questionScores = questionScoreMapper.selectListBySubmitIds(submitIds);
            //计算年级分数排名
            Map<Double, Integer> gradeRanks = calculateGradeRank(submits);
            if (classId != null && classId > 0) {
                submits = submits.stream().filter(s-> s.getClassId().equals(classId)).collect(Collectors.toList());
            }
            for (StudentSubmit submit : submits) {
                Map<String, Object> detail = new HashMap<>();
                // 基本信息
                detail.put("class", classInfo.getClassName());
                detail.put("studentNo", submit.getStudentNum());
                detail.put("name", submit.getStudentName());
                detail.put("totalScore", CommonUtils.formatNumber(submit.getScore()));
                detail.put("gradeRank", gradeRanks.get(submit.getScore()));
                // 获取题目得分详情
                List<QuestionScore> submitScoreList = questionScores.stream().filter(qs -> qs.getStudentSubmitId().equals(submit.getId())).collect(Collectors.toList());
                // 分别统计客观题和主观题
                double objectiveScore = 0;
                double subjectiveScore = 0;
                Map<String, Double> objectiveMap = new TreeMap<>(new QuestionKeyComparator());
                Map<String, String> objectiveAnswerMap = new TreeMap<>(new QuestionKeyComparator());
                Map<String, Double> subjectiveMap = new TreeMap<>(new SubQuestionKeyComparator());

                for (QuestionScore qs : submitScoreList) {
                    QuestionInfo questionInfo = questionInfos.stream().filter(q-> q.getQuestionId().equals(qs.getQuestionId())).findFirst().orElse(null);
                    int bigQuestionNum = CalculateQuestionNumUtil.bigQuestionNum(questionInfo.getQuestionNum().intValue());
                    int smallQuestionNum = CalculateQuestionNumUtil.smallQuestionNum(questionInfo.getQuestionNum().intValue());
                    if (questionInfo.getIsSubjectiveItem() == 0) {  // 客观题
                        objectiveScore += qs.getScore();
                        if(!ObjectUtils.isEmpty(questionInfo.getQuestionAlias())){
                            objectiveMap.put(questionInfo.getQuestionTypeName() + questionInfo.getQuestionAlias(), qs.getScore());
                            objectiveAnswerMap.put(questionInfo.getQuestionTypeName() + questionInfo.getQuestionAlias(), qs.getStudentAnswer());
                        }else {
                            if (smallQuestionNum != 0) {
                                objectiveMap.put(bigQuestionNum + "-" + questionInfo.getQuestionTypeName() + "-" + smallQuestionNum, qs.getScore());
                                objectiveAnswerMap.put(bigQuestionNum + "-" + questionInfo.getQuestionTypeName() + "-" + smallQuestionNum, qs.getStudentAnswer());
                            } else {
                                objectiveMap.put(questionInfo.getQuestionTypeName() + "-" + bigQuestionNum, qs.getScore());
                                objectiveAnswerMap.put(questionInfo.getQuestionTypeName() + "-" + bigQuestionNum, qs.getStudentAnswer());
                            }
                        }
                    } else {  // 主观题
                        subjectiveScore += qs.getScore();
                        if(!ObjectUtils.isEmpty(questionInfo.getQuestionAlias())){
                            subjectiveMap.put(questionInfo.getQuestionTypeName() + questionInfo.getQuestionAlias(), qs.getScore());
                        }else {
                            if (smallQuestionNum != 0) {
                                subjectiveMap.put(bigQuestionNum + "-" + questionInfo.getQuestionTypeName() + "-" + smallQuestionNum, qs.getScore());
                            } else {
                                subjectiveMap.put(questionInfo.getQuestionTypeName() + "-" + bigQuestionNum, qs.getScore());
                            }
                        }
                    }
                }

                detail.put("objectiveScore", CommonUtils.formatNumber(objectiveScore));
                detail.put("subjectiveScore", CommonUtils.formatNumber(subjectiveScore));
                detail.put("objectiveMap", objectiveMap);
                detail.put("subjectiveMap", subjectiveMap);
                detail.put("objectiveAnswerMap", objectiveAnswerMap);

                result.add(detail);
            }

            // 按照 totalScore 正序排序
            result.sort((m1, m2) -> {
                double score1 = Double.parseDouble((String) m1.get("totalScore"));
                double score2 = Double.parseDouble((String) m2.get("totalScore"));
                return Double.compare(score2, score1);
            });
            //map按照总分计算排名
            mapRank(result);
            return result;
        } catch (Exception e) {
            log.error("计算作业得分详情失败: {}", e.getMessage(), e);
            throw new RuntimeException("计算作业得分详情失败: " + e.getMessage());
        }
    }

    /**
     * 下载成绩单
     *
     * @param examDetail
     * @param classInfo
     * @return
     */
    public List<Map<String, Object>> calculateScoreDetails(ExamDetail examDetail, ClassInfo classInfo) {
        try {
            List<Map<String, Object>> result = new ArrayList<>();
            List<StudentSubmit> submits = studentSubmitMapper.selectListByExamDetailId(examDetail.getId());
            //按照
            if(submits.isEmpty()){
                return result;
            }
            List<QuestionInfo> questionInfos = questionInfoMapper.selectByExamDetailId(examDetail.getId());
            // 过滤有效提交
            submits = submits.stream()
                    .filter(s -> s.getSubmitStatus() == 1)
                    .collect(Collectors.toList());
            List<Long> submitIds = submits.stream().map(StudentSubmit::getId).collect(Collectors.toList());
            List<QuestionScore> questionScores = questionScoreMapper.selectListBySubmitIds(submitIds);
            //计算年级分数排名
            Map<Double, Integer> gradeRanks = calculateGradeRank(submits);
            if (classInfo.getClassId() != null && classInfo.getClassId() > 0) {
                submits = submits.stream().filter(s-> s.getClassId().equals(classInfo.getClassId())).collect(Collectors.toList());
            }
            for (StudentSubmit submit : submits) {
                Map<String, Object> detail = new HashMap<>();
                // 基本信息
                detail.put("class", classInfo.getClassName());
                detail.put("studentNo", submit.getStudentNum());
                detail.put("name", submit.getStudentName());
                detail.put("totalScore", CommonUtils.formatNumber(submit.getScore()));
                detail.put("gradeRank", gradeRanks.get(submit.getScore()));
                // 获取题目得分详情
                List<QuestionScore> submitScoreList = questionScores.stream().filter(qs -> qs.getStudentSubmitId().equals(submit.getId())).collect(Collectors.toList());
                // 分别统计客观题和主观题
                double objectiveScore = 0;
                double subjectiveScore = 0;
                Map<String, Double> objectiveMap = new TreeMap<>(new QuestionKeyComparator());
                Map<String, String> objectiveAnswerMap = new TreeMap<>(new QuestionKeyComparator());
                Map<String, Double> subjectiveMap = new TreeMap<>(new SubQuestionKeyComparator());

                for (QuestionScore qs : submitScoreList) {
                    QuestionInfo questionInfo = questionInfos.stream().filter(q-> q.getQuestionId().equals(qs.getQuestionId())).findFirst().orElse(null);
                    int bigQuestionNum = CalculateQuestionNumUtil.bigQuestionNum(questionInfo.getQuestionNum().intValue());
                    int smallQuestionNum = CalculateQuestionNumUtil.smallQuestionNum(questionInfo.getQuestionNum().intValue());
                    if (questionInfo.getIsSubjectiveItem() == 0) {  // 客观题
                        objectiveScore += qs.getScore();
                        if(!ObjectUtils.isEmpty(questionInfo.getQuestionAlias())){
                            objectiveMap.put(questionInfo.getQuestionTypeName() + questionInfo.getQuestionAlias(), qs.getScore());
                            objectiveAnswerMap.put(questionInfo.getQuestionTypeName() + questionInfo.getQuestionAlias(), qs.getStudentAnswer());
                        }else {
                            if (smallQuestionNum != 0) {
                                objectiveMap.put(bigQuestionNum + "-" + questionInfo.getQuestionTypeName() + "-" + smallQuestionNum, qs.getScore());
                                objectiveAnswerMap.put(bigQuestionNum + "-" + questionInfo.getQuestionTypeName() + "-" + smallQuestionNum, qs.getStudentAnswer());
                            } else {
                                objectiveMap.put(questionInfo.getQuestionTypeName() + "-" + bigQuestionNum, qs.getScore());
                                objectiveAnswerMap.put(questionInfo.getQuestionTypeName() + "-" + bigQuestionNum, qs.getStudentAnswer());
                            }
                        }
                    } else {  // 主观题
                        subjectiveScore += qs.getScore();
                        if(!ObjectUtils.isEmpty(questionInfo.getQuestionAlias())){
                            objectiveMap.put(questionInfo.getQuestionTypeName() + questionInfo.getQuestionAlias(), qs.getScore());
                            objectiveAnswerMap.put(questionInfo.getQuestionTypeName() + questionInfo.getQuestionAlias(), qs.getStudentAnswer());
                        }else {
                            if (smallQuestionNum != 0) {
                                subjectiveMap.put(bigQuestionNum + "-" + questionInfo.getQuestionTypeName() + "-" + smallQuestionNum, qs.getScore());
                            } else {
                                subjectiveMap.put(questionInfo.getQuestionTypeName() + "-" + bigQuestionNum, qs.getScore());
                            }
                        }
                    }
                }

                detail.put("objectiveScore", CommonUtils.formatNumber(objectiveScore));
                detail.put("subjectiveScore", CommonUtils.formatNumber(subjectiveScore));
                detail.put("objectiveMap", objectiveMap);
                detail.put("subjectiveMap", subjectiveMap);
                detail.put("objectiveAnswerMap", objectiveAnswerMap);

                result.add(detail);
            }

            // 按照 totalScore 正序排序
            result.sort((m1, m2) -> {
                double score1 = Double.parseDouble((String) m1.get("totalScore"));
                double score2 = Double.parseDouble((String) m2.get("totalScore"));
                return Double.compare(score2, score1);
            });
            //map按照总分计算排名
            mapRank(result);
            return result;
        } catch (Exception e) {
            log.error("计算作业得分详情失败: {}", e.getMessage(), e);
            throw new RuntimeException("计算作业得分详情失败: " + e.getMessage());
        }
    }

    /**
     * 下载成绩单
     *
     * @param examDetail
     * @param classInfo
     * @return
     */
    public List<Map<String, Object>> calculateScoreDetailsExcel(ExamDetail examDetail, ClassInfo classInfo) {
        try {
            List<Map<String, Object>> result = new ArrayList<>();
            List<StudentSubmit> submits = studentSubmitMapper.selectListByExamDetailId(examDetail.getId());
            //按照
            if(submits.isEmpty()){
                return result;
            }
            List<QuestionInfo> questionInfos = questionInfoMapper.selectByExamDetailId(examDetail.getId());
            // 过滤有效提交
            submits = submits.stream()
                    .filter(s -> s.getSubmitStatus() == 1)
                    .collect(Collectors.toList());
            List<Long> submitIds = submits.stream().map(StudentSubmit::getId).collect(Collectors.toList());
            List<QuestionScore> questionScores = questionScoreMapper.selectListBySubmitIds(submitIds);
            //计算年级分数排名
            Map<Double, Integer> gradeRanks = calculateGradeRank(submits);
            if (classInfo.getClassId() != null && classInfo.getClassId() > 0) {
                submits = submits.stream().filter(s-> s.getClassId().equals(classInfo.getClassId())).collect(Collectors.toList());
            }
            for (StudentSubmit submit : submits) {
                Map<String, Object> detail = new HashMap<>();
                // 基本信息
                detail.put("class", classInfo.getClassName());
                detail.put("studentNo", submit.getStudentNum());
                detail.put("name", submit.getStudentName());
                detail.put("totalScore", CommonUtils.formatNumber(submit.getScore()));
                detail.put("gradeRank", gradeRanks.get(submit.getScore()));
                // 获取题目得分详情
                List<QuestionScore> submitScoreList = questionScores.stream().filter(qs -> qs.getStudentSubmitId().equals(submit.getId())).collect(Collectors.toList());
                // 分别统计客观题和主观题
                double objectiveScore = 0;
                double subjectiveScore = 0;
                Map<String, Double> objectiveMap = new TreeMap<>(new QuestionKeyComparator());
                Map<String, String> objectiveAnswerMap = new TreeMap<>(new QuestionKeyComparator());
                Map<String, Double> subjectiveMap = new TreeMap<>(new SubQuestionKeyComparator());

                for (QuestionScore qs : submitScoreList) {
                    QuestionInfo questionInfo = questionInfos.stream().filter(q-> q.getQuestionId().equals(qs.getQuestionId())).findFirst().orElse(null);
                    int bigQuestionNum = CalculateQuestionNumUtil.bigQuestionNum(questionInfo.getQuestionNum().intValue());
                    int smallQuestionNum = CalculateQuestionNumUtil.smallQuestionNum(questionInfo.getQuestionNum().intValue());
                    if (questionInfo.getIsSubjectiveItem() == 0) {  // 客观题
                        objectiveScore += qs.getScore();
                        if(!ObjectUtils.isEmpty(questionInfo.getQuestionAlias())){
                            objectiveMap.put(questionInfo.getQuestionAlias(), qs.getScore());
                        }else {
                            if (smallQuestionNum != 0) {
                                objectiveMap.put(bigQuestionNum + "-" + smallQuestionNum, qs.getScore());
                                objectiveAnswerMap.put(bigQuestionNum + "-" + smallQuestionNum, qs.getStudentAnswer());
                            } else {
                                objectiveMap.put(String.valueOf(bigQuestionNum), qs.getScore());
                                objectiveAnswerMap.put(String.valueOf(bigQuestionNum), qs.getStudentAnswer());
                            }
                        }
                    } else {  // 主观题
                        subjectiveScore += qs.getScore();
                        if(!ObjectUtils.isEmpty(questionInfo.getQuestionAlias())){
                            subjectiveMap.put(questionInfo.getQuestionAlias(), qs.getScore());
                        }else {
                            if (smallQuestionNum != 0) {
                                subjectiveMap.put(bigQuestionNum + "-" + smallQuestionNum, qs.getScore());
                            } else {
                                subjectiveMap.put(String.valueOf(bigQuestionNum), qs.getScore());
                            }
                        }
                    }
                }

                detail.put("objectiveScore", CommonUtils.formatNumber(objectiveScore));
                detail.put("subjectiveScore", CommonUtils.formatNumber(subjectiveScore));
                detail.put("objectiveMap", objectiveMap);
                detail.put("subjectiveMap", subjectiveMap);
                detail.put("objectiveAnswerMap", objectiveAnswerMap);

                result.add(detail);
            }

            // 按照 totalScore 正序排序
            result.sort((m1, m2) -> {
                double score1 = Double.parseDouble((String) m1.get("totalScore"));
                double score2 = Double.parseDouble((String) m2.get("totalScore"));
                return Double.compare(score2, score1);
            });
            //map按照总分计算排名
            mapRank(result);
            return result;
        } catch (Exception e) {
            log.error("计算作业得分详情失败: {}", e.getMessage(), e);
            throw new RuntimeException("计算作业得分详情失败: " + e.getMessage());
        }
    }

    private Map<Double, Integer> calculateGradeRank(List<StudentSubmit> submits) {
        // 按分数降序排序并分组计数
        Map<Double, Long> scoreCountMap = submits.stream()
                .filter(s -> !ObjectUtils.isEmpty(s.getScore())) // 过滤空分数
                .collect(Collectors.groupingBy(
                        StudentSubmit::getScore,
                        Collectors.counting()
                ));
        // 按分数降序排列并计算排名
        List<Double> sortedScores = new ArrayList<>(scoreCountMap.keySet());
        sortedScores.sort(Comparator.reverseOrder()); // 降序排列
        // 计算排名
        Map<Double, Integer> gradeRank = new LinkedHashMap<>(); // 保持顺序
        int currentRank = 1;
        for (Double score : sortedScores) {
            gradeRank.put(score, currentRank);
            currentRank += scoreCountMap.get(score).intValue(); // 跳过相同分数的人数
        }
        return gradeRank;
    }

    private static void mapRank(List<Map<String, Object>> result) {
        // 添加rank字段
        int rank = 1;
        int sameScoreCount = 1;
        double prevScore = Double.parseDouble((String) result.get(0).get("totalScore"));
        for (int i = 0; i < result.size(); i++) {
            Map<String, Object> item = result.get(i);
            double currentScore = Double.parseDouble((String) item.get("totalScore"));

            if (i > 0 && currentScore < prevScore) {
                rank += sameScoreCount;
                sameScoreCount = 1;
            } else if (i > 0 && currentScore == prevScore) {
                sameScoreCount++;
            }

            item.put("rank", rank);
            prevScore = currentScore;
        }
    }

    /**
     * 原始分成绩及排名
     * @param examId
     * @param classIds
     * @return
     */
    public List<Map<String, Object>> calculateGradeScoreDetails(Long examId, List<Long> classIds) {
        try {
            ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
            // 获取学生提交记录
            List<StudentSubmit> submits = studentSubmitMapper.selectsdByExamDetailId(examDetail.getId());
            if(ObjectUtils.isEmpty(classIds)){
                classIds = submits.stream().map(StudentSubmit::getClassId).collect(Collectors.toList()).stream().distinct().collect(Collectors.toList());
            }
            List<Long> finalClassIds = classIds;
            submits.stream().filter(s -> s.getSubmitStatus() == 1 && finalClassIds.contains(s.getClassId())).collect(Collectors.toList());
            // 过滤有效提交
            submits = submits.stream()
                    .filter(s -> s.getSubmitStatus() == 1)
                    .collect(Collectors.toList());

            // 按总分排序，用于计算全体排名
            List<StudentSubmit> sortedAllSubmits = new ArrayList<>(submits);
            sortedAllSubmits.sort((s1, s2) -> Double.compare(s2.getScore(), s1.getScore()));

            // 计算全体排名映射（处理同分情况）
            Map<Double, Integer> overallRankMap = new HashMap<>();
            int currentRank = 1;
            for (int i = 0; i < sortedAllSubmits.size(); i++) {
                double currentScore = sortedAllSubmits.get(i).getScore();
                if (!overallRankMap.containsKey(currentScore)) {
                    overallRankMap.put(currentScore, currentRank);
                }
                currentRank = i + 2;  // 下一个不同分数的排名
            }

            // 按班级分组，用于计算班级排名
            Map<Long, List<StudentSubmit>> classSubmits = submits.stream()
                    .collect(Collectors.groupingBy(StudentSubmit::getClassId));

            // 对每个班级计算排名映射（处理同分情况）
            Map<Long, Map<Double, Integer>> classRankMaps = new HashMap<>();
            classSubmits.forEach((classId, classSubs) -> {
                classSubs.sort((s1, s2) -> Double.compare(s2.getScore(), s1.getScore()));
                Map<Double, Integer> classRankMap = new HashMap<>();
                int rank = 1;
                for (int i = 0; i < classSubs.size(); i++) {
                    double score = classSubs.get(i).getScore();
                    if (!classRankMap.containsKey(score)) {
                        classRankMap.put(score, rank);
                    }
                    rank = i + 2;  // 下一个不同分数的排名
                }
                classRankMaps.put(classId, classRankMap);
            });

            List<Long> submitIds = submits.stream().map(StudentSubmit::getId).collect(Collectors.toList());
            List<QuestionScore> questionScores = questionScoreMapper.selectListBySubmitIds(submitIds);
            List<Long> questionIds = questionScores.stream().map(QuestionScore::getQuestionId).collect(Collectors.toList());
            List<QuestionInfo> questionInfoList = questionInfoMapper.selectListByQuestionIds(questionIds);
            List<Map<String, Object>> result = new ArrayList<>();
            for (StudentSubmit submit : submits) {
                Map<String, Object> detail = new HashMap<>();
                // 基本信息
                detail.put("class", submit.getClassName());
                detail.put("studentNo", submit.getStudentNum());
                detail.put("name", submit.getStudentName());
                detail.put("totalScore", CommonUtils.formatNumber(submit.getScore()));

                // 获取全体排名（考虑同分情况）
                int overallRank = overallRankMap.get(submit.getScore());
                detail.put("overallRank", overallRank);

                // 获取班级排名（考虑同分情况）
                Map<Double, Integer> classRankMap = classRankMaps.get(submit.getClassId());
                int classRank = classRankMap.get(submit.getScore());
                detail.put("classRank", classRank);

                // 获取题目得分详情
                List<QuestionScore> studentQuestionScores = questionScores.stream().filter(q-> q.getStudentSubmitId().equals(submit.getId())).collect(Collectors.toList());
                // 分别统计客观题和主观题
                double objectiveScore = 0;
                double subjectiveScore = 0;
                List<Map<String, Object>> objectiveMap = new ArrayList<>();
                List<Map<String, Object>> subjectiveMap = new ArrayList<>();

                for (QuestionScore qs : studentQuestionScores) {
                    QuestionInfo questionInfo = questionInfoList.stream().filter(qi -> qi.getQuestionId().equals(qs.getQuestionId())).findFirst().orElse(null);
                    if (questionInfo.getIsSubjectiveItem() == 0) {  // 客观题
                        Map<String, Object> objectMap = new HashMap<>();
                        objectiveScore += qs.getScore();
                        if(!ObjectUtils.isEmpty(questionInfo.getQuestionAlias())){
                            objectMap.put("questionNum", questionInfo.getQuestionTypeName() + "-" + questionInfo.getQuestionAlias());
                        }else {
                            int bigQuestionNum = CalculateQuestionNumUtil.bigQuestionNum(questionInfo.getQuestionNum());
                            int smallQuestionNum = CalculateQuestionNumUtil.smallQuestionNum(questionInfo.getQuestionNum());
                            if (smallQuestionNum != 0) {
                                objectMap.put("questionNum", bigQuestionNum + "-" + questionInfo.getQuestionTypeName() + "-" + smallQuestionNum);
                            } else {
                                objectMap.put("questionNum", questionInfo.getQuestionTypeName() + "-" + bigQuestionNum);
                            }
                        }
                        objectMap.put("score", qs.getScore());
                        objectiveMap.add(objectMap);
                    } else {  // 主观题
                        Map<String, Object> subjectMap = new HashMap<>();
                        subjectiveScore += qs.getScore();
                        if(!ObjectUtils.isEmpty(questionInfo.getQuestionAlias())){
                            subjectMap.put("questionNum", questionInfo.getQuestionTypeName() + "-" + questionInfo.getQuestionAlias());
                        }else {
                            int bigQuestionNum = CalculateQuestionNumUtil.bigQuestionNum(questionInfo.getQuestionNum());
                            int smallQuestionNum = CalculateQuestionNumUtil.smallQuestionNum(questionInfo.getQuestionNum());
                            if (smallQuestionNum != 0) {
                                subjectMap.put("questionNum", bigQuestionNum + "-" + questionInfo.getQuestionTypeName() + "-" + smallQuestionNum);
                            } else {
                                subjectMap.put("questionNum", questionInfo.getQuestionTypeName() + "-" + bigQuestionNum);
                            }
                        }
                        subjectMap.put("score", qs.getScore());
                        subjectiveMap.add(subjectMap);
                    }
                }
                detail.put("objectiveScore", CommonUtils.formatNumber(objectiveScore));
                detail.put("subjectiveScore", CommonUtils.formatNumber(subjectiveScore));
                detail.put("objectiveMap", objectiveMap);
                detail.put("subjectiveMap", subjectiveMap);
                result.add(detail);
            }
            // 按照 totalScore 正序排序
            result.sort((m1, m2) -> {
                double score1 = Double.parseDouble((String) m1.get("totalScore"));
                double score2 = Double.parseDouble((String) m2.get("totalScore"));
                return Double.compare(score2, score1);
            });

            return result;
        } catch (Exception e) {
            log.error("计算作业得分详情失败: {}", e.getMessage(), e);
            throw new RuntimeException("计算作业得分详情失败: " + e.getMessage());
        }
    }

    /**
     * 原始分成绩及排名
     * @param examId
     * @param classIds
     * @return
     */
    public List<Map<String, Object>> calculateGradeScoreDetailsExcel(Long examId, List<Long> classIds) {
        try {
            ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
            // 获取学生提交记录
            List<StudentSubmit> submits = studentSubmitMapper.selectsdByExamDetailId(examDetail.getId());
            if(ObjectUtils.isEmpty(classIds)){
                classIds = submits.stream().map(StudentSubmit::getClassId).collect(Collectors.toList()).stream().distinct().collect(Collectors.toList());
            }
            List<Long> finalClassIds = classIds;
            submits.stream().filter(s -> s.getSubmitStatus() == 1 && finalClassIds.contains(s.getClassId())).collect(Collectors.toList());
            // 过滤有效提交
            submits = submits.stream()
                    .filter(s -> s.getSubmitStatus() == 1)
                    .collect(Collectors.toList());

            // 按总分排序，用于计算全体排名
            List<StudentSubmit> sortedAllSubmits = new ArrayList<>(submits);
            sortedAllSubmits.sort((s1, s2) -> Double.compare(s2.getScore(), s1.getScore()));

            // 计算全体排名映射（处理同分情况）
            Map<Double, Integer> overallRankMap = new HashMap<>();
            int currentRank = 1;
            for (int i = 0; i < sortedAllSubmits.size(); i++) {
                double currentScore = sortedAllSubmits.get(i).getScore();
                if (!overallRankMap.containsKey(currentScore)) {
                    overallRankMap.put(currentScore, currentRank);
                }
                currentRank = i + 2;  // 下一个不同分数的排名
            }

            // 按班级分组，用于计算班级排名
            Map<Long, List<StudentSubmit>> classSubmits = submits.stream()
                    .collect(Collectors.groupingBy(StudentSubmit::getClassId));

            // 对每个班级计算排名映射（处理同分情况）
            Map<Long, Map<Double, Integer>> classRankMaps = new HashMap<>();
            classSubmits.forEach((classId, classSubs) -> {
                classSubs.sort((s1, s2) -> Double.compare(s2.getScore(), s1.getScore()));
                Map<Double, Integer> classRankMap = new HashMap<>();
                int rank = 1;
                for (int i = 0; i < classSubs.size(); i++) {
                    double score = classSubs.get(i).getScore();
                    if (!classRankMap.containsKey(score)) {
                        classRankMap.put(score, rank);
                    }
                    rank = i + 2;  // 下一个不同分数的排名
                }
                classRankMaps.put(classId, classRankMap);
            });

            List<Long> submitIds = submits.stream().map(StudentSubmit::getId).collect(Collectors.toList());
            List<QuestionScore> questionScores = questionScoreMapper.selectListBySubmitIds(submitIds);
            List<Long> questionIds = questionScores.stream().map(QuestionScore::getQuestionId).collect(Collectors.toList());
            List<QuestionInfo> questionInfoList = questionInfoMapper.selectListByQuestionIds(questionIds);
            List<Map<String, Object>> result = new ArrayList<>();
            for (StudentSubmit submit : submits) {
                Map<String, Object> detail = new HashMap<>();
                // 基本信息
                detail.put("class", submit.getClassName());
                detail.put("studentNo", submit.getStudentNum());
                detail.put("name", submit.getStudentName());
                detail.put("totalScore", CommonUtils.formatNumber(submit.getScore()));

                // 获取全体排名（考虑同分情况）
                int overallRank = overallRankMap.get(submit.getScore());
                detail.put("overallRank", overallRank);

                // 获取班级排名（考虑同分情况）
                Map<Double, Integer> classRankMap = classRankMaps.get(submit.getClassId());
                int classRank = classRankMap.get(submit.getScore());
                detail.put("classRank", classRank);

                // 获取题目得分详情
                List<QuestionScore> studentQuestionScores = questionScores.stream().filter(q-> q.getStudentSubmitId().equals(submit.getId())).collect(Collectors.toList());
                // 分别统计客观题和主观题
                double objectiveScore = 0;
                double subjectiveScore = 0;
                List<Map<String, Object>> objectiveMap = new ArrayList<>();
                List<Map<String, Object>> subjectiveMap = new ArrayList<>();

                for (QuestionScore qs : studentQuestionScores) {
                    QuestionInfo questionInfo = questionInfoList.stream().filter(qi -> qi.getQuestionId().equals(qs.getQuestionId())).findFirst().orElse(null);
                    if (questionInfo.getIsSubjectiveItem() == 0) {  // 客观题
                        Map<String, Object> objectMap = new HashMap<>();
                        objectiveScore += qs.getScore();
                        if(!ObjectUtils.isEmpty(questionInfo.getQuestionAlias())){
                            objectMap.put("questionNum",  questionInfo.getQuestionAlias());
                        }else {
                            int bigQuestionNum = CalculateQuestionNumUtil.bigQuestionNum(questionInfo.getQuestionNum());
                            int smallQuestionNum = CalculateQuestionNumUtil.smallQuestionNum(questionInfo.getQuestionNum());
                            if (smallQuestionNum != 0) {
                                objectMap.put("questionNum", bigQuestionNum + "-" + smallQuestionNum);
                            } else {
                                objectMap.put("questionNum", bigQuestionNum);
                            }
                        }
                        objectMap.put("score", qs.getScore());
                        objectiveMap.add(objectMap);
                    } else {  // 主观题
                        Map<String, Object> subjectMap = new HashMap<>();
                        subjectiveScore += qs.getScore();
                        if(!ObjectUtils.isEmpty(questionInfo.getQuestionAlias())){
                            subjectMap.put("questionNum", questionInfo.getQuestionAlias());
                        }else {
                            int bigQuestionNum = CalculateQuestionNumUtil.bigQuestionNum(questionInfo.getQuestionNum());
                            int smallQuestionNum = CalculateQuestionNumUtil.smallQuestionNum(questionInfo.getQuestionNum());
                            if (smallQuestionNum != 0) {
                                subjectMap.put("questionNum", bigQuestionNum + "-" + smallQuestionNum);
                            } else {
                                subjectMap.put("questionNum", bigQuestionNum);
                            }
                        }
                        subjectMap.put("score", qs.getScore());
                        subjectiveMap.add(subjectMap);
                    }
                }
                detail.put("objectiveScore", CommonUtils.formatNumber(objectiveScore));
                detail.put("subjectiveScore", CommonUtils.formatNumber(subjectiveScore));
                detail.put("objectiveMap", objectiveMap);
                detail.put("subjectiveMap", subjectiveMap);
                result.add(detail);
            }
            // 按照 totalScore 正序排序
            result.sort((m1, m2) -> {
                double score1 = Double.parseDouble((String) m1.get("totalScore"));
                double score2 = Double.parseDouble((String) m2.get("totalScore"));
                return Double.compare(score2, score1);
            });

            return result;
        } catch (Exception e) {
            log.error("计算作业得分详情失败: {}", e.getMessage(), e);
            throw new RuntimeException("计算作业得分详情失败: " + e.getMessage());
        }
    }


    public List<Map<String, Object>> calculateErrorQuestions(Long examId, Long classId, Integer startRate, Integer endRate) {
        try {
            ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
            if (examDetail == null) {
                throw new RuntimeException("未找到考试详情");
            }
            //获取所有学生的得分情况 按照isRight进行分组
            List<Map<String, Object>> questionAnswerList = questionScoreMapper.selectQuestionAnswerList(examDetail.getId());
            // 获取所有题目得分情况
            List<Map<String, Object>> examQuestionStats = questionScoreMapper.selectQuestionStats(examDetail.getId());
            List<QuestionRight> questionRightList = new ArrayList<>();
            List<Map<String, Object>> questionStats;
            if(!ObjectUtils.isEmpty(classId)) {
                ClassInfo classInfo = classInfoMapper.selectByClassId(classId, examDetail.getId());
                if(classInfo == null) {
                    throw new RuntimeException("未找到班级详情");
                }
                questionStats = questionScoreMapper.selectQuestionStatsByExamDetailIdAndClassDetailId(examDetail.getId(), classId);
                questionAnswerList = questionAnswerList.stream().filter(qa-> qa.get("classId").equals(classId)).collect(Collectors.toList());
                Map<Object, List<Map<String, Object>>> questionMap = questionAnswerList.stream()
                        .collect(Collectors.groupingBy(map->map.get("questionId")));
                questionMap.forEach((k,v)->{
                    QuestionRight questionRight = new QuestionRight();
                    questionRight.setQuestionId(Long.valueOf(k.toString()));
                    //按照isRight分组
                    Map<Object, List<Map<String, Object>>> rightList = v.stream()
                            .collect(Collectors.groupingBy(map-> map.get("isRight")));
                    List<Right> rights = new ArrayList<>();
                    rightList.forEach((k2, v2)->{
                        Right right = new Right();
                        right.setIsRight(k2.toString());
                        List<String> studentList = new ArrayList<>();
                        for(Map<String, Object> map: v2){
                            Object studentNameObj = map.get("studentName");
                            if(!ObjectUtils.isEmpty(studentNameObj)){
                                studentList.add(studentNameObj.toString());
                            }
                        }
                        right.setStudentList(studentList);
                        rights.add(right);
                    });
                    questionRight.setRights(rights);
                    questionRightList.add(questionRight);
                });
            }else {
                questionStats = examQuestionStats;
            }
            questionStats.forEach(q -> {
                q.put("examScoreRate", examQuestionStats.stream().filter(e-> e.get("questionId").equals(q.get("questionId")))
                        .collect(Collectors.toList()).get(0).getOrDefault("scoreRate", "-"));
            });

            // 获取所有题目ID
            List<String> questionBankIds = questionStats.stream()
                    .map(q -> q.get("questionBankId").toString())
                    .collect(Collectors.toList());

            log.info("准备获取知识点信息，题目IDs: {}", questionBankIds);

            // 调用知识点接口
            try {
                ResponseEntity<Map> response = sendPost(questionBankIds);
                if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                    Map<String, Object> responseBody = response.getBody();
                    if(ObjectUtils.isEmpty(responseBody.get("data"))){
                        return new ArrayList<>();
                    }
                    List<Map<String, Object>> questionDataList = (List<Map<String, Object>>) responseBody.get("data");
                    if (questionDataList == null || questionDataList.isEmpty()) {
                        log.warn("知识点接口返回空数据");
                        questionStats.forEach(q -> q.put("knowledge", "-"));
                    } else {
                        log.info("成功获取到{}个题目的知识点信息", questionDataList.size());
                        // 创建知识点映射
                        Map<String, String> knowledgeMap = new HashMap<>();
                        Map<String, String> degreeMap = new HashMap<>();
                        for (Map<String, Object> questionData : questionDataList) {
                            List<Map<String, Object>> knowledgeList = (List<Map<String, Object>>) questionData.get("questionKnowledgeChapterRelList");
                            String degree = questionData.containsKey("degree") && questionData.get("degree") != null
                                    ? questionData.get("degree").toString()
                                    : "";
                            String difficulty = questionData.containsKey("difficulty") && questionData.get("difficulty") != null
                                    ? questionData.get("difficulty").toString()
                                    : "";
                            if (knowledgeList != null && !knowledgeList.isEmpty()) {
                                String questionUuid = knowledgeList.get(0).get("questionUuid").toString();
                                // 将多个知识点用逗号连接
                                String knowledgePoints = knowledgeList.stream()
                                        .map(k -> k.get("knowledgeName").toString())
                                        .collect(Collectors.joining("、"));
                                knowledgeMap.put(questionUuid, knowledgePoints);
                                degreeMap.put(questionUuid, difficulty + "-" + degree);
                            }
                        }
                        // 合并知识点信息到题目统计数据
                        questionStats.forEach(q -> {
                            String questionId = q.get("questionBankId").toString();
                            q.put("knowledge", knowledgeMap.getOrDefault(questionId, "-"));
                            q.put("degree", degreeMap.getOrDefault(questionId, "-"));
                        });
                    }
                } else {
                    log.error("知识点接口返回错误状态码: {}", response.getStatusCode());
                    questionStats.forEach(q -> q.put("knowledge", "-"));
                }
            } catch (Exception e) {
                log.error("获取试题知识点失败: {}, URL: {}", e.getMessage(),
                        baseUrl + "/system/question/info/knowledge/" + questionBankIds, e);
                questionStats.forEach(q -> q.put("knowledge", "-"));
            }

            // 筛选得分率低于阈值的题目
            List<Map<String, Object>> filteredStats = questionStats.stream()
                    .filter(q -> {
                        Double scoreRate = (Double) q.get("scoreRate");
                        if(!ObjectUtils.isEmpty(q.get("questionAlias"))){
                            q.put("questionNum", q.get("questionTypeName") + "-" + q.get("questionAlias"));
                        }else {
                            int bigQuestionNum = CalculateQuestionNumUtil.bigQuestionNum((Integer) q.get("questionNum"));
                            int smallQuestionNum = CalculateQuestionNumUtil.smallQuestionNum((Integer) q.get("questionNum"));
                            if (smallQuestionNum != 0) {
                                q.put("questionNum", bigQuestionNum + "-" + q.get("questionTypeName") + smallQuestionNum);
                            } else {
                                q.put("questionNum", q.get("questionTypeName") + "-" + bigQuestionNum);
                            }
                        }
                        return scoreRate >= startRate && scoreRate <= endRate;
                    })
                    .collect(Collectors.toList());
            for (Map<String, Object> map : filteredStats) {
                List<QuestionRight> rights = questionRightList.stream().filter(qr-> map.get("questionId").equals(qr.getQuestionId())).collect(Collectors.toList());
                QuestionRight questionRight = new QuestionRight();
                if(!rights.isEmpty()){
                    questionRight = rights.get(0);
                }
                map.put("answerRight", questionRight);
            }
            log.info("找到{}个得分率低于{}%的题目", filteredStats.size(), endRate);
            return filteredStats;

        } catch (Exception e) {
            log.error("计算高频错题统计失败: {}", e.getMessage(), e);
            throw new RuntimeException("计算高频错题统计失败: " + e.getMessage());
        }
    }

    public Map<String, Object> calculateHomeworkQuality(Long examId, Long classId) {
        try {
            ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
            if (examDetail == null) {
                throw new RuntimeException("未找到考试详情");
            }

            // 获取学生提交记录
            List<StudentSubmit> submits = studentSubmitMapper.selectByExamAndClass(examDetail.getId(), classId);
            submits = submits.stream()
                    .filter(s -> s.getSubmitStatus() != null && s.getSubmitStatus() == 1)
                    .collect(Collectors.toList());

            if (submits.isEmpty()) {
                return createEmptyResult(examDetail.getFullScore());
            }

            // 计算各项指标
            double avgScore = submits.stream()
                    .mapToDouble(StudentSubmit::getScore)
                    .average()
                    .orElse(0.0);
            double difficulty = examDetail.getFullScore() > 0 ? avgScore / examDetail.getFullScore() : 0;

            double reliability = calculateSplitHalfReliability(submits);
            double discrimination = calculateDiscriminationIndex(submits, examDetail.getFullScore());

            Map<String, Object> result = new HashMap<>();
            result.put("fullScore", examDetail.getFullScore());
            result.put("submitCount", submits.size());
            result.put("avgScore", CommonUtils.formatNumber(avgScore));
            result.put("difficulty", CommonUtils.formatNumber(difficulty));
            result.put("reliability", CommonUtils.formatNumber(reliability));
            result.put("discrimination", CommonUtils.formatNumber(discrimination));

            // 评价结果
            List<Map<String, Object>> evaluations = new ArrayList<>();

            // 难度评价
            Map<String, Object> difficultyMap = new HashMap<>();
            difficultyMap.put("indicator", "难度");
            String difficultyDesc = "";
            if (difficulty <= 0.2) {
                difficultyDesc = "试题困难";
            }  else if (difficulty > 0.2 && difficulty <= 0.4) {
                difficultyDesc = "试题较难";
            } else if (difficulty > 0.4 && difficulty <= 0.6) {
                difficultyDesc = "试题一般";
            } else if (difficulty > 0.6 && difficulty <= 0.8) {
                difficultyDesc = "试题较易";
            } else {
                difficultyDesc = "试题容易";
            }
            difficultyMap.put("paperEvaluation", difficultyDesc);
            difficultyMap.put("questionEvaluation", calculateQuestionDifficultyDistribution(submits));
            evaluations.add(difficultyMap);

            // 信度评价
            Map<String, Object> reliabilityMap = new HashMap<>();
            reliabilityMap.put("indicator", "信度");
            String reliabilityDesc = "";
            if (reliability < 0.7) {
                reliabilityDesc = "信度较低(<0.7)，不宜使用";
            } else if (reliability < 0.85) {
                reliabilityDesc = "信度良好(0.7~0.85)，可用于团体比较";
            } else {
                reliabilityDesc = "信度优秀(>0.85)，可用于个体比较";
            }
            reliabilityMap.put("paperEvaluation", reliabilityDesc);
            reliabilityMap.put("questionEvaluation", "");  // 题目信度不适用
            evaluations.add(reliabilityMap);

            // 区分度评价
            Map<String, Object> discriminationMap = new HashMap<>();
            discriminationMap.put("indicator", "区分度");
            String discriminationDesc = "";
            if (discrimination < 0.2) {
                discriminationDesc = "区分度差(<0.2)，建议淘汰";
            } else if (discrimination < 0.3) {
                discriminationDesc = "区分度不太好(0.2~0.29)，需要修改";
            } else if (discrimination < 0.4) {
                discriminationDesc = "区分度较好(0.3~0.39)";
            } else {
                discriminationDesc = "区分度很好(>0.4)";
            }
            discriminationMap.put("paperEvaluation", discriminationDesc);
            discriminationMap.put("questionEvaluation", calculateQuestionDiscriminationDistribution(submits));
            evaluations.add(discriminationMap);

            result.put("evaluations", evaluations);
            return result;

        } catch (Exception e) {
            log.error("计算作业质量失败", e);
            throw new RuntimeException("计算作业质量失败: " + e.getMessage());
        }
    }

    // 创建空结果
    private Map<String, Object> createEmptyResult(Integer fullScore) {

        Map<String, Object> emptyResult = new HashMap<>();
        emptyResult.put("fullScore", fullScore);
        emptyResult.put("submitCount", 0);
        emptyResult.put("avgScore", "0.00");
        emptyResult.put("difficulty", "0.00");
        emptyResult.put("reliability", "0.00");
        emptyResult.put("discrimination", "0.00");
        emptyResult.put("evaluations", Collections.emptyList());
        return emptyResult;
    }

    // 计算标准差
    private double calculateStandardDeviation(List<StudentSubmit> submits) {
        if (submits == null || submits.isEmpty()) {
            return 0.0;
        }

        double mean = submits.stream()
                .mapToDouble(StudentSubmit::getScore)
                .average()
                .orElse(0.0);

        double variance = submits.stream()
                .mapToDouble(s -> Math.pow(s.getScore() - mean, 2))
                .average()
                .orElse(0.0);

        return Math.sqrt(variance);
    }

    // 计算相关系数
    private double calculateCorrelation(List<Double> x, List<Double> y, List<Long> submitIds) {
        if (x.size() != y.size() || x.isEmpty()) {
            return 0.0;
        }
        int n = submitIds.size();
        double numerator = 0.0;
        double denominatorX = 0.0;
        double denominatorY = 0.0;
        double sumX = 0.0;
        double sumY = 0.0;
        for (int i = 0; i < x.size(); i++) {
            double diffX = x.get(i);
            double diffY = y.get(i);
            numerator += diffX * diffY;
            sumX += diffX;
            sumY += diffY;
            denominatorX += diffX * diffX;
            denominatorY += diffY * diffY;
        }
        double up = n * numerator - sumX * sumY;
        double down = Math.sqrt((n * denominatorX - sumX * sumX) * (n * denominatorY - sumY * sumY));
        if (denominatorX <= 0 || denominatorY <= 0) {
            return 0.0;
        }
        return up / down;
    }


    public List<Map<String, Object>> calculateQuestionScoreRates(Long examId, Long classId) {
        try {
            // 获取考试详情
            ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
            if (examDetail == null) {
                throw new RuntimeException("未找到考试详情");
            }
            ClassInfo classInfo = classInfoMapper.selectByClassId(classId, examDetail.getId());
            // 获取所有题目信息
            List<QuestionInfo> questions = questionInfoMapper.selectByExamDetailId(examDetail.getId());
            Map<Long, QuestionInfo> questionMap = questions.stream()
                    .collect(Collectors.toMap(QuestionInfo::getQuestionId, q -> q));

            // 获取所有学生提交记录
            List<StudentSubmit> examSubmits = studentSubmitMapper.selectByExamDetailId(examDetail.getId())
                    .stream()
                    .filter(s -> s.getSubmitStatus() == 1)
                    .collect(Collectors.toList());

            // 如果指定了班级，获取班级数据
            List<StudentSubmit> classSubmits = examSubmits.stream()
                    .filter(submit -> submit.getClassInfoId().equals(classInfo.getId()))
                    .collect(Collectors.toList());


            List<Map<String, Object>> result = new ArrayList<>();

            // 计算全部数据
            Map<String, Object> totalData = new HashMap<>();
            totalData.put("type", "0");
            totalData.put("name", "全体");
            totalData.put("questionList", calculateQuestionStats(examSubmits, questions, questionMap));
            result.add(totalData);

            // 如果有班级数据，计算班级数据
            if (classSubmits != null) {
                Map<String, Object> classData = new HashMap<>();
                classData.put("type", "1");
                classData.put("name", classInfo.getClassName());
                classData.put("questionList", calculateQuestionStats(classSubmits, questions, questionMap));
                result.add(classData);
            }

            return result;
        } catch (Exception e) {
            log.error("计算试题得分率失败", e);
            throw new RuntimeException("计算试题得分率失败: " + e.getMessage());
        }
    }

    private List<Map<String, Object>> calculateQuestionStats(List<StudentSubmit> submits,
            List<QuestionInfo> questions, Map<Long, QuestionInfo> questionMap) {
        // 获取所有题目得分
        List<QuestionScore> allScores = new ArrayList<>();
        for (StudentSubmit submit : submits) {
            List<QuestionScore> scores = questionScoreMapper.selectByStudentSubmitId(submit.getId());
            allScores.addAll(scores);
        }

        // 按题目分组计算得分率
        Map<Long, List<QuestionScore>> scoresByQuestion = allScores.stream()
                .collect(Collectors.groupingBy(QuestionScore::getQuestionId));

        List<Map<String, Object>> result = new ArrayList<>();
        for (QuestionInfo question : questions) {
            Map<String, Object> questionRate = new TreeMap<>();
            List<QuestionScore> scores = scoresByQuestion.getOrDefault(question.getQuestionId(), new ArrayList<>());

            // 计算平均分
            double avgScore = scores.stream()
                    .mapToDouble(QuestionScore::getScore)
                    .average()
                    .orElse(0.0);

            // 计算得分率
            double scoreRate = avgScore / question.getQuestionScore() * 100;
            if(scoreRate <= 40){
                questionRate.put("flag", 0);
            }else {
                questionRate.put("flag", 1);
            }
            if(!ObjectUtils.isEmpty(question.getQuestionAlias())){
                questionRate.put("questionNum", question.getQuestionTypeName() + "-" + question.getQuestionAlias());
            }else {
                int bigQuestionNum = CalculateQuestionNumUtil.bigQuestionNum(question.getQuestionNum());
                int smallQuestionNum = CalculateQuestionNumUtil.smallQuestionNum(question.getQuestionNum());
                if (smallQuestionNum != 0) {
                    questionRate.put("questionNum", bigQuestionNum + "-" + question.getQuestionTypeName() + "-" + smallQuestionNum);
                } else {
                    questionRate.put("questionNum", question.getQuestionTypeName() + "-" + bigQuestionNum);
                }
            }
            questionRate.put("questionType", question.getQuestionTypeName());
            questionRate.put("scoreRate", String.format("%.1f", scoreRate));
            questionRate.put("avgScore", String.format("%.1f", avgScore));
            questionRate.put("fullScore", question.getQuestionScore());

            result.add(questionRate);
        }
        // 使用自定义比较器排序
        Collections.sort(result, new QuestionNumComparator());
        return result;
    }
    //题型题号排序
    public static class QuestionNumComparator implements Comparator<Map<String, Object>> {
        // 正则表达式匹配两种主要格式
        // 格式1：数字-题型-数字（如45-解答题-1）
        private static final Pattern PATTERN_GROUP_TYPE_NUM = Pattern.compile("^(\\d+)-(.*?)-(\\d+)$");
        // 格式2：题型-数字（如单选题-1）
        private static final Pattern PATTERN_TYPE_NUM = Pattern.compile("^(.*?)-(\\d+)$");

        @Override
        public int compare(Map<String, Object> data1, Map<String, Object> data2) {
            String num1 = (String) data1.get("questionNum");
            String num2 = (String) data2.get("questionNum");

            // 解析两个questionNum的信息
            QuestionPart part1 = parseQuestionNum(num1);
            QuestionPart part2 = parseQuestionNum(num2);

            // 1. 先按题型排序（如"单选题"排在"解答题"之前，按字符串自然顺序）
            int typeCompare = part1.type.compareTo(part2.type);
            if (typeCompare != 0) {
                return typeCompare;
            }

            // 2. 题型相同，按组号排序（格式1中的前缀数字，如45-解答题-1中的45）
            if (part1.groupNum != part2.groupNum) {
                return Integer.compare(part1.groupNum, part2.groupNum);
            }

            // 3. 组号相同，按小题号排序（如单选题-1中的1，解答题-2中的2）
            return Integer.compare(part1.itemNum, part2.itemNum);
        }

        /**
         * 解析questionNum为结构化信息
         * @param questionNum 题号字符串（如"45-解答题-1"、"单选题-2"）
         * @return 包含题型、组号、小题号的对象
         */
        private QuestionPart parseQuestionNum(String questionNum) {
            // 匹配格式1：数字-题型-数字（如45-解答题-1）
            Matcher matcherGroup = PATTERN_GROUP_TYPE_NUM.matcher(questionNum);
            if (matcherGroup.matches()) {
                int groupNum = Integer.parseInt(matcherGroup.group(1)); // 组号（45）
                String type = matcherGroup.group(2); // 题型（解答题）
                int itemNum = Integer.parseInt(matcherGroup.group(3)); // 小题号（1）
                return new QuestionPart(type, groupNum, itemNum);
            }

            // 匹配格式2：题型-数字（如单选题-1）
            Matcher matcherType = PATTERN_TYPE_NUM.matcher(questionNum);
            if (matcherType.matches()) {
                String type = matcherType.group(1); // 题型（单选题）
                int itemNum = Integer.parseInt(matcherType.group(2)); // 小题号（1）
                return new QuestionPart(type, 0, itemNum); // 组号为0（无组号时用0）
            }

            // 若都不匹配，按原始字符串处理（避免排序报错）
            return new QuestionPart(questionNum, 0, 0);
        }

        /**
         * 封装questionNum的解析结果
         */
        private static class QuestionPart {
            String type; // 题型（如"单选题"、"解答题"）
            int groupNum; // 组号（格式1中的前缀数字，如45-解答题-1中的45）
            int itemNum; // 小题号（如单选题-1中的1）

            public QuestionPart(String type, int groupNum, int itemNum) {
                this.type = type;
                this.groupNum = groupNum;
                this.itemNum = itemNum;
            }
        }
    }

    public List<Map<String, Object>> calculateQuestionAnalysis(Long examId, Long classId) {
        try {
            // 获取考试详情
            ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
            if (examDetail == null) {
                throw new RuntimeException("未找到考试详情");
            }

            // 获取所有学生提交记录
            List<StudentSubmit> examSubmits = studentSubmitMapper.selectByExamDetailId(examDetail.getId())
                    .stream()
                    .filter(s -> s.getSubmitStatus() == 1)
                    .collect(Collectors.toList());

            // 如果指定了班级，获取班级数据
            List<StudentSubmit> classSubmits = null;
            if (classId != null && classId > 0) {
                ClassInfo classInfo = classInfoMapper.selectByExamDetailIdAndClassId(examDetail.getId(), classId);
                if (classInfo == null) {
                    throw new RuntimeException("未找到班级信息");
                }
                classSubmits = examSubmits.stream()
                    .filter(submit -> submit.getClassInfoId().equals(classInfo.getId()))
                    .collect(Collectors.toList());
            }

            // 获取所有题目信息
            List<QuestionInfo> questions = questionInfoMapper.selectByExamDetailId(examDetail.getId());

            // 按题号排序
            questions.sort(Comparator.comparing(QuestionInfo::getQuestionNum));

            List<Map<String, Object>> result = new ArrayList<>();

            // 计算全部数据
            Map<String, Object> totalData = new HashMap<>();
            totalData.put("type", "0");
            totalData.put("name", "全体");
            totalData.put("questionList", calculateQuestionAnalysisStats(examSubmits, questions));
            result.add(totalData);

            // 如果有班级数据，计算班级数据
            if (classSubmits != null) {
                Map<String, Object> classData = new HashMap<>();
                classData.put("type", "1");
                ClassInfo classInfo = classInfoMapper.selectByExamDetailIdAndClassId(examDetail.getId(), classId);
                classData.put("name", classInfo != null ? classInfo.getClassName() : "未知班级");
                classData.put("questionList", calculateQuestionAnalysisStats(classSubmits, questions));
                result.add(classData);
            }

            return result;
        } catch (Exception e) {
            log.error("计算小题分析失败", e);
            throw new RuntimeException("计算小题分析失败: " + e.getMessage());
        }
    }

    private List<Map<String, Object>> calculateQuestionAnalysisStats(List<StudentSubmit> submits, List<QuestionInfo> questions) {
        // 获取所有题目得分
        List<QuestionScore> allScores = new ArrayList<>();
        for (StudentSubmit submit : submits) {
            List<QuestionScore> scores = questionScoreMapper.selectByStudentSubmitId(submit.getId());
            allScores.addAll(scores);
        }

        // 按题目分组计算得分率
        Map<Long, List<QuestionScore>> scoresByQuestion = allScores.stream()
                .collect(Collectors.groupingBy(QuestionScore::getQuestionId));

        List<Map<String, Object>> result = new ArrayList<>();

        for (QuestionInfo question : questions) {
            Map<String, Object> questionAnalysis = new HashMap<>();
            List<QuestionScore> scores = scoresByQuestion.getOrDefault(question.getQuestionId(), new ArrayList<>());

            // 计算平均分
            double avgScore = scores.stream()
                    .mapToDouble(QuestionScore::getScore)
                    .average()
                    .orElse(0.0);

            // 计算得分率
            double scoreRate = avgScore / question.getQuestionScore() * 100;
            if(!ObjectUtils.isEmpty(question.getQuestionAlias())){
                questionAnalysis.put("questionNum", question.getQuestionTypeName() + "-" + question.getQuestionAlias());
            }else {
                int bigQuestionNum = CalculateQuestionNumUtil.bigQuestionNum(question.getQuestionNum());
                int smallQuestionNum = CalculateQuestionNumUtil.smallQuestionNum(question.getQuestionNum());
                if (smallQuestionNum != 0) {
                    questionAnalysis.put("questionNum", bigQuestionNum + "-" + question.getQuestionTypeName() + "-" + smallQuestionNum);
                } else {
                    questionAnalysis.put("questionNum", question.getQuestionTypeName() + "-" + bigQuestionNum);
                }
            }
            questionAnalysis.put("scoreRate", String.format("%.1f", scoreRate));

            result.add(questionAnalysis);
        }

        return result;
    }


    public List<Map<String, Object>> calculateObjectiveAnswerDistribution(Long examId, Long classId) {
        try {
            // 获取考试详情
            ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
            if (examDetail == null) {
                throw new RuntimeException("未找到考试详情");
            }

            // 获取所有客观题信息
            List<QuestionInfo> questions = questionInfoMapper.selectByExamDetailId(examDetail.getId())
                    .stream()
                    .filter(q -> q.getIsSubjectiveItem() == 0)
                    .sorted(Comparator.comparing(QuestionInfo::getQuestionNum))
                    .collect(Collectors.toList());
            List<StudentSubmit> submits = studentSubmitMapper.selectByExamDetailId(examDetail.getId())
                    .stream()
                    .filter(s -> s.getSubmitStatus() == 1)  // 只统计有效提交
                    .collect(Collectors.toList());
            // 批量获取所有题目的得分记录
            List<Long> submitIds = submits.stream()
                    .map(StudentSubmit::getId)
                    .collect(Collectors.toList());
            List<QuestionScore> allScores = questionScoreMapper.selectByStudentSubmitIds(submitIds);
            List<QuestionScore> examAllScores = allScores;
            // 获取学生提交记录
            if (classId != null && classId > 0) {
                List<StudentSubmit> classSubmits = submits.stream().filter(s-> s.getClassId().equals(classId)).collect(Collectors.toList());
                List<Long> classSubmitIds = classSubmits.stream().map(StudentSubmit::getId).collect(Collectors.toList());
                allScores = allScores.stream().filter(qs-> classSubmitIds.contains(qs.getStudentSubmitId())).collect(Collectors.toList());
            }
            // 按题目ID分组
            Map<Long, List<QuestionScore>> scoresByQuestionId = allScores.stream()
                    .collect(Collectors.groupingBy(QuestionScore::getQuestionId));
            List<Map<String, Object>> result = new ArrayList<>();
            for (QuestionInfo question : questions) {
                //计算年级的得分率
                List<QuestionScore> examscores = examAllScores.stream().filter(qs-> qs.getQuestionId().equals(question.getQuestionId())).collect(Collectors.toList());
                //取出正确作答的人数
                List<QuestionScore> rightQuestions = examscores.stream().filter(qs-> qs.getIsRight() == 1).collect(Collectors.toList());
                double examscoreRate = (double) rightQuestions.size() / examscores.size() * 100;
                Map<String, Object> distribution = new HashMap<>();
                List<QuestionScore> scores = scoresByQuestionId.getOrDefault(question.getQuestionId(), new ArrayList<>());
                if (!scores.isEmpty()) {
                    double avgScore = scores.stream().mapToDouble(QuestionScore::getScore).average().orElse(0.0);
                    // 计算答对的人数
                    int classRightnum = scores.stream().filter(qs-> qs.getIsRight() == 1).collect(Collectors.toList()).size();
                    //计算正答率
                    double scoreRate = (double)classRightnum / scores.size() * 100;
                    // 计算满分率
                    long fullScoreCount = scores.stream()
                            .filter(s -> s.getScore() >= question.getQuestionScore())
                            .count();
                    double fullScoreRate = (double) fullScoreCount / scores.size() * 100;

                    // 计算零分率
                    long zeroScoreCount = scores.stream()
                            .filter(s -> s.getScore() == 0)
                            .count();
                    double zeroScoreRate = (double) zeroScoreCount / scores.size() * 100;
                    if(!ObjectUtils.isEmpty(question.getQuestionAlias())){
                        distribution.put("questionNum", question.getQuestionTypeName() + "-" + question.getQuestionAlias());
                    }else {
                        int bigQuestionNum = CalculateQuestionNumUtil.bigQuestionNum(question.getQuestionNum());
                        int smallQuestionNum = CalculateQuestionNumUtil.smallQuestionNum(question.getQuestionNum());
                        if (smallQuestionNum != 0) {
                            distribution.put("questionNum", bigQuestionNum + "-" + question.getQuestionTypeName() + "-" + smallQuestionNum);
                        } else {
                            distribution.put("questionNum", question.getQuestionTypeName() + "-" + bigQuestionNum);
                        }
                    }
                    distribution.put("answer", question.getQuestionAnswer());
                    distribution.put("score", question.getQuestionScore());
                    distribution.put("avgScore", String.format("%.2f", avgScore));
                    distribution.put("scoreRate", String.format("%.2f", scoreRate));
                    distribution.put("fullScoreRate", String.format("%.2f", fullScoreRate));
                    distribution.put("zeroScoreRate", String.format("%.2f", zeroScoreRate));
                    distribution.put("studentAnswer", getObjectiveAnswerDistribution(scores));
                    distribution.put("examScoreRate", String.format("%.2f", examscoreRate));

                    result.add(distribution);
                }
            }

            return result;
        } catch (Exception e) {
            log.error("计算客观题作答分布失败", e);
            throw new RuntimeException("计算客观题作答分布失败: " + e.getMessage());
        }
    }


    public List<Map<String, Object>> calculateSubjectiveAnswerDistribution(Long examId, Long classId) {
        // 同样的优化方式应用到主观题分布计算
        try {
            ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
            if (examDetail == null) {
                throw new RuntimeException("未找到考试详情");
            }
            // 获取所有客观题信息
            List<QuestionInfo> questions = questionInfoMapper.selectByExamDetailId(examDetail.getId())
                    .stream()
                    .filter(q -> q.getIsSubjectiveItem() == 1)
                    .sorted(Comparator.comparing(QuestionInfo::getQuestionNum))
                    .collect(Collectors.toList());
            List<StudentSubmit> submits = studentSubmitMapper.selectByExamDetailId(examDetail.getId())
                    .stream()
                    .filter(s -> s.getSubmitStatus() == 1)  // 只统计有效提交
                    .collect(Collectors.toList());
            // 批量获取所有题目的得分记录
            List<Long> submitIds = submits.stream()
                    .map(StudentSubmit::getId)
                    .collect(Collectors.toList());
            List<QuestionScore> allScores = questionScoreMapper.selectByStudentSubmitIds(submitIds);
            List<QuestionScore> examAllScores = allScores;
            // 获取学生提交记录
            if (classId != null && classId > 0) {
                List<StudentSubmit> classSubmits = submits.stream().filter(s-> s.getClassId().equals(classId)).collect(Collectors.toList());
                List<Long> classSubmitIds = classSubmits.stream().map(StudentSubmit::getId).collect(Collectors.toList());
                allScores = allScores.stream().filter(qs-> classSubmitIds.contains(qs.getStudentSubmitId())).collect(Collectors.toList());
            }
            // 按题目ID分组
            Map<Long, List<QuestionScore>> scoresByQuestionId = allScores.stream()
                    .collect(Collectors.groupingBy(QuestionScore::getQuestionId));
            List<Map<String, Object>> result = new ArrayList<>();
            for (QuestionInfo question : questions) {
                Map<String, Object> distribution = new HashMap<>();
                //计算年级的得分率
                List<QuestionScore> examscores = examAllScores.stream().filter(qs-> qs.getQuestionId().equals(question.getQuestionId())).collect(Collectors.toList());
                //计算全体平均分
                double examAvgScore = examscores.stream()
                        .mapToDouble(QuestionScore::getScore)
                        .average()
                        .orElse(0.0);
                // 计算全体得分率
                double examscoreRate = examAvgScore / question.getQuestionScore() * 100;
                List<QuestionScore> scores = scoresByQuestionId.getOrDefault(question.getQuestionId(), new ArrayList<>());
                if (!scores.isEmpty()) {
                    // 计算平均分
                    double avgScore = scores.stream()
                            .mapToDouble(QuestionScore::getScore)
                            .average()
                            .orElse(0.0);
                    // 计算得分率
                    double scoreRate = avgScore / question.getQuestionScore() * 100;

                    // 计算满分率
                    long fullScoreCount = scores.stream()
                            .filter(s -> s.getScore() >= question.getQuestionScore())
                            .count();
                    double fullScoreRate = (double) fullScoreCount / scores.size() * 100;

                    // 计算零分率
                    long zeroScoreCount = scores.stream()
                            .filter(s -> s.getScore() == 0)
                            .count();
                    double zeroScoreRate = (double) zeroScoreCount / scores.size() * 100;
                    if(!ObjectUtils.isEmpty(question.getQuestionAlias())){
                        distribution.put("questionNum", question.getQuestionTypeName() + "-" + question.getQuestionAlias());
                    }else {
                        int bigQuestionNum = CalculateQuestionNumUtil.bigQuestionNum(question.getQuestionNum());
                        int smallQuestionNum = CalculateQuestionNumUtil.smallQuestionNum(question.getQuestionNum());
                        if (smallQuestionNum != 0) {
                            distribution.put("questionNum", bigQuestionNum + "-" + question.getQuestionTypeName() + "-" + smallQuestionNum);
                        } else {
                            distribution.put("questionNum", question.getQuestionTypeName() + "-" + bigQuestionNum);
                        }
                    }
                    distribution.put("answer", question.getQuestionAnswer()!= null? question.getQuestionAnswer() : "-");
                    distribution.put("score", question.getQuestionScore());
                    distribution.put("avgScore", String.format("%.2f", avgScore));
                    distribution.put("scoreRate", String.format("%.2f", scoreRate));
                    distribution.put("fullScoreRate", String.format("%.2f", fullScoreRate));
                    distribution.put("zeroScoreRate", String.format("%.2f", zeroScoreRate));
                    distribution.put("studentAnswer", getSubjectiveScoreDistribution(scores, question.getQuestionScore()));
                    distribution.put("examScoreRate", String.format("%.2f", examscoreRate));
                    result.add(distribution);
                }
            }

            return result;
        } catch (Exception e) {
            log.error("计算主观题作答分布失败", e);
            throw new RuntimeException("计算主观题作答分布失败: " + e.getMessage());
        }
    }

    private String getSubjectiveScoreDistribution(List<QuestionScore> scores, double fullScore) {
        List<String> distributions = new ArrayList<>();
        long total = scores.size();

        if (fullScore <= 0) {
            return "";
        }

        // 根据满分值确定分段方式
        if (fullScore == 1) {
            // 1分：(0-1) 1
            long count0_1 = getScoreRangeCount(scores, 0, 1);
            long count1 = getScoreRangeCount(scores, 1, 1);
            distributions.add(String.format("(0-1)占(%.2f%%)", (count0_1 * 100.0) / total));
            distributions.add(String.format("1分占(%.2f%%)", (count1 * 100.0) / total));
        } else if (fullScore == 2) {
            // 2分：(0-1) (1-2) 2
            long count0_1 = getScoreRangeCount(scores, 0, 1);
            long count1_2 = getScoreRangeCount(scores, 1, 2);
            long count2 = getScoreRangeCount(scores, 2, 2);
            distributions.add(String.format("(0-1)占(%.2f%%)", (count0_1 * 100.0) / total));
            distributions.add(String.format("(1-2)占(%.2f%%)", (count1_2 * 100.0) / total));
            distributions.add(String.format("2分占(%.2f%%)", (count2 * 100.0) / total));
        } else if (fullScore == 3) {
            // 3分：(0-1) (1-2) (2-3) 3
            long count0_1 = getScoreRangeCount(scores, 0, 1);
            long count1_2 = getScoreRangeCount(scores, 1, 2);
            long count2_3 = getScoreRangeCount(scores, 2, 3);
            long count3 = getScoreRangeCount(scores, 3, 3);
            distributions.add(String.format("(0-1)占(%.2f%%)", (count0_1 * 100.0) / total));
            distributions.add(String.format("(1-2)占(%.2f%%)", (count1_2 * 100.0) / total));
            distributions.add(String.format("(2-3)占(%.2f%%)", (count2_3 * 100.0) / total));
            distributions.add(String.format("3分占(%.2f%%)", (count3 * 100.0) / total));
        } else if (fullScore == 4) {
            // 4分：(0-1) (1-2) (2-3) (3-4) 4
            long count0_1 = getScoreRangeCount(scores, 0, 1);
            long count1_2 = getScoreRangeCount(scores, 1, 2);
            long count2_3 = getScoreRangeCount(scores, 2, 3);
            long count3_4 = getScoreRangeCount(scores, 3, 4);
            long count4 = getScoreRangeCount(scores, 4, 4);
            distributions.add(String.format("(0-1)占(%.2f%%)", (count0_1 * 100.0) / total));
            distributions.add(String.format("(1-2)占(%.2f%%)", (count1_2 * 100.0) / total));
            distributions.add(String.format("(2-3)占(%.2f%%)", (count2_3 * 100.0) / total));
            distributions.add(String.format("(3-4)占(%.2f%%)", (count3_4 * 100.0) / total));
            distributions.add(String.format("4分占(%.2f%%)", (count4 * 100.0) / total));
        } else {
            // ≥5分：按照X÷4=Y计算分段
            int segmentSize = (int) Math.ceil(fullScore / 4.0);
            for (int i = 0; i < 4; i++) {
                double start = i * segmentSize;
                if(start > fullScore){
                    start = fullScore;
                }
                double end = Math.min((i + 1) * segmentSize, fullScore);
                if (i == 3) {
                    // 最后一段包含满分
                    long count = getScoreRangeCount(scores, start, fullScore);
                    distributions.add(String.format("[%.0f-%.0f]占(%.2f%%)", start, fullScore, (count * 100.0) / total));
                } else {
                    long count = getScoreRangeCount(scores, start, end);
                    distributions.add(String.format("[%.0f-%.0f)占(%.2f%%)", start, end, (count * 100.0) / total));
                }
            }
        }

        return String.join(" ", distributions);
    }


    public Map<String, Object> calculateErrorDistribution(Long examId, Long classId, Integer isSubjective) {
        try {
            ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
            if (examDetail == null) {
                throw new RuntimeException("未找到考试详情");
            }

            // 获取题目信息
            List<QuestionInfo> questions = questionInfoMapper.selectByExamDetailId(examDetail.getId())
                    .stream()
                    .filter(q -> q.getIsSubjectiveItem().equals(isSubjective))
                    .sorted(Comparator.comparing(QuestionInfo::getQuestionNum))
                    .collect(Collectors.toList());
            if(questions.isEmpty()){
                return new HashMap<>();
            }

            List<Map<String, Object>> questionStats = new ArrayList<>();
            List<Long> questionIds = questions.stream().map(QuestionInfo::getQuestionId).collect(Collectors.toList());
            List<QuestionScore> questionScores = questionScoreMapper.selectByExamDetailIdAndQuestionIds(examDetail.getId(), questionIds);
            //计算全体得分率
            List<QuestionScore> examQuestionScores = questionScores;
            if(!ObjectUtils.isEmpty(classId)){
                ClassInfo classInfo = classInfoMapper.selectByExamDetailIdAndClassId(examDetail.getId(), classId);
                if(classInfo != null) {
                    List<StudentSubmit> submits = studentSubmitMapper.selectByClassInfoId(examDetail.getId(), classInfo.getId());
                    if (!ObjectUtils.isEmpty(submits)) {
                        List<Long> submitIds = submits.stream().map(StudentSubmit::getId).collect(Collectors.toList());
                        questionScores = questionScores.stream().filter(qs -> submitIds.contains(qs.getStudentSubmitId())).collect(Collectors.toList());
                    }
                }
            }
            Map<Long, List<QuestionScore>> mapQuestionId2List = questionScores.stream().collect(Collectors.groupingBy(QuestionScore::getQuestionId));
            List<String> questionBankIds = questions.stream().map(QuestionInfo::getQuestionBankId).collect(Collectors.toList());
            ResponseEntity<Map> response = sendPost(questionBankIds);
            // 创建知识点映射
            Map<String, String> knowledgeMap = new HashMap<>();
            Map<String, String> degreeMap = new HashMap<>();
            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                Map<String, Object> responseBody = response.getBody();
                if(!ObjectUtils.isEmpty(responseBody.get("data"))) {
                    List<Map<String, Object>> questionDataList = (List<Map<String, Object>>) responseBody.get("data");
                    for (Map<String, Object> questionData : questionDataList) {
                        List<Map<String, Object>> knowledgeList = (List<Map<String, Object>>) questionData.get("questionKnowledgeChapterRelList");
                        String degree = questionData.containsKey("degree") && questionData.get("degree") != null
                                ? questionData.get("degree").toString()
                                : "";
                        String difficulty = questionData.containsKey("difficulty") && questionData.get("difficulty") != null
                                ? questionData.get("difficulty").toString()
                                : "";
                        if (knowledgeList != null && !knowledgeList.isEmpty()) {
                            String questionUuid = knowledgeList.get(0).get("questionUuid").toString();
                            // 将多个知识点用逗号连接
                            String knowledgePoints = knowledgeList.stream()
                                    .map(k -> k.get("knowledgeName").toString())
                                    .collect(Collectors.joining("、"));
                            knowledgeMap.put(questionUuid, knowledgePoints);
                            degreeMap.put(questionUuid, difficulty + "-" + degree);
                        }
                    }
                }
            }
            for (QuestionInfo question : questions) {
                List<QuestionScore> questionScoreList = examQuestionScores.stream().filter(qs-> qs.getQuestionId().equals(question.getQuestionId())).collect(Collectors.toList());
                double examAvg = questionScoreList.stream()
                        .mapToDouble(QuestionScore::getScore) // 提取分数
                        .average()                            // 计算平均值
                        .orElse(0.0);
                double examScoreRate = examAvg / question.getQuestionScore() * 100;
                Map<String, Object> stat = new HashMap<>();
                if(mapQuestionId2List.isEmpty()){
                    continue;
                }
                List<QuestionScore> scores = mapQuestionId2List.get(question.getQuestionId());
                if (!scores.isEmpty()) {
                    double avgScore = scores.stream()
                            .mapToDouble(QuestionScore::getScore)
                            .average()
                            .orElse(0.0);

                    // 计算得分率
                    double scoreRate;
                    if (question.getIsSubjectiveItem() == 1) {
                        // 主观题：使用平均分/满分
                        scoreRate = avgScore / question.getQuestionScore() * 100;
                    } else {
                        // 客观题：使用正确率
                        scoreRate = scores.stream()
                                .filter(s -> Math.abs(s.getScore() - question.getQuestionScore()) < 0.0001)
                                .count() * 100.0 / scores.size();
                    }
                    // 计算难度

                    if(!ObjectUtils.isEmpty(question.getQuestionAlias())){
                        stat.put("questionNum", question.getQuestionTypeName() +"-"+ question.getQuestionAlias());
                    }else {
                        int bigQuestionNum = CalculateQuestionNumUtil.bigQuestionNum(question.getQuestionNum());
                        int smallQuestionNum = CalculateQuestionNumUtil.smallQuestionNum(question.getQuestionNum());
                        if (smallQuestionNum != 0) {
                            stat.put("questionNum", bigQuestionNum + "-" + question.getQuestionTypeName() + "-" + smallQuestionNum);
                        } else {
                            stat.put("questionNum", question.getQuestionTypeName() + "-" + bigQuestionNum);
                        }
                    }
                    stat.put("questionId", question.getQuestionId());
                    stat.put("scoreRate", String.format("%.2f", scoreRate));
                    stat.put("difficulty", degreeMap.getOrDefault(question.getQuestionBankId(), "-"));
                    stat.put("questionTypeName", question.getQuestionTypeName());
                    stat.put("questionPointName", knowledgeMap.getOrDefault(question.getQuestionBankId(), "-"));
                    stat.put("score", question.getQuestionScore());
                    stat.put("isSubjective", question.getIsSubjectiveItem());
                    stat.put("questionBankId", question.getQuestionBankId());
                    stat.put("examScoreRate", String.format("%.2f", examScoreRate));

                    questionStats.add(stat);
                }
            }

            Map<String, Object> result = new HashMap<>();
            result.put("questions", questionStats);
            return result;
        } catch (Exception e) {
            log.error("计算错题分布失败", e);
            throw new RuntimeException("计算错题分布失败: " + e.getMessage());
        }
    }


    public List<Map<String, Object>> calculateQuestionMatrix(Long examId, Long classId) {
        try {
            ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
            if (examDetail == null) {
                throw new RuntimeException("未找到考试详情");
            }

            // 获取所有题目信息
            List<QuestionInfo> questions = questionInfoMapper.selectByExamDetailId(examDetail.getId());

            // 获取有效的学生提交记录
            List<StudentSubmit> submits = studentSubmitMapper.selectByExamAndClass(examDetail.getId(), classId)
                    .stream()
                    .filter(s -> s.getSubmitStatus() == 1)
                    .collect(Collectors.toList());

            // 获取所有提交ID
            List<Long> submitIds = submits.stream()
                    .map(StudentSubmit::getId)
                    .collect(Collectors.toList());

            // 批量获取所有题目得分
            Map<Long, List<QuestionScore>> questionScoresMap = new HashMap<>();
            if (!submitIds.isEmpty()) {
                List<QuestionScore> allScores = questionScoreMapper.selectByStudentSubmitIds(submitIds);
                questionScoresMap = allScores.stream()
                        .collect(Collectors.groupingBy(QuestionScore::getQuestionId));
            }

            List<Map<String, Object>> result = new ArrayList<>();

            List<String> questionBankIds = questions.stream().map(QuestionInfo::getQuestionBankId).collect(Collectors.toList());
            ResponseEntity<Map> response = sendPost(questionBankIds);
            // 创建知识点映射
            Map<String, String> knowledgeMap = new HashMap<>();
            Map<String, String> degreeMap = new HashMap<>();
            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                Map<String, Object> responseBody = response.getBody();
                if(ObjectUtils.isEmpty(responseBody.get("data"))){
                    return new ArrayList<>();
                }
                List<Map<String, Object>> questionDataList = (List<Map<String, Object>>) responseBody.get("data");

                for (Map<String, Object> questionData : questionDataList) {
                    List<Map<String, Object>> knowledgeList = (List<Map<String, Object>>) questionData.get("questionKnowledgeChapterRelList");
                    String degree = questionData.containsKey("degree") && questionData.get("degree") != null
                            ? questionData.get("degree").toString()
                            : "";
                    String difficulty = questionData.containsKey("difficulty") && questionData.get("difficulty") != null
                            ? questionData.get("difficulty").toString()
                            : "";
                    if (knowledgeList != null && !knowledgeList.isEmpty()) {
                        String questionUuid = knowledgeList.get(0).get("questionUuid").toString();
                        // 将多个知识点用逗号连接
                        String knowledgePoints = knowledgeList.stream()
                                .map(k -> k.get("knowledgeName").toString())
                                .collect(Collectors.joining("、"));
                        knowledgeMap.put(questionUuid, knowledgePoints);
                        degreeMap.put(questionUuid, difficulty + "-" + degree);
                    }
                }
            }
            // 按题目统计
            for (QuestionInfo question : questions) {
                Map<String, Object> questionStats = new HashMap<>();
                questionStats.put("type", question.getQuestionTypeName() != null ? question.getQuestionTypeName() : "未知题型");
                if(!ObjectUtils.isEmpty(question.getQuestionAlias())){
                    questionStats.put("number", question.getQuestionTypeName() + "-" + question.getQuestionAlias());
                }else {
                    int bigQuestionNum = CalculateQuestionNumUtil.bigQuestionNum(question.getQuestionNum());
                    int smallQuestionNum = CalculateQuestionNumUtil.smallQuestionNum(question.getQuestionNum());
                    if (smallQuestionNum != 0) {
                        questionStats.put("number", bigQuestionNum + "-" + question.getQuestionTypeName() + "-" + smallQuestionNum);
                    } else {
                        questionStats.put("number", question.getQuestionTypeName() + "-" + bigQuestionNum);
                    }
                }
                questionStats.put("score", question.getQuestionScore());
                questionStats.put("knowledge", knowledgeMap.getOrDefault(question.getQuestionBankId(), "-")); // 知识点待补充

                // 从Map中获取该题目的所有得分记录
                List<QuestionScore> scores = questionScoresMap.getOrDefault(question.getQuestionId(), Collections.emptyList());

                if (!scores.isEmpty()) {
                    // 计算难度
                    String degreeValue = degreeMap.getOrDefault(question.getQuestionBankId(), "");
                    if (degreeValue.contains("-")) {
                        degreeValue = degreeValue.substring(0, degreeValue.indexOf("-"));
                    }
                    questionStats.put("difficulty", degreeValue);

                    // 计算满分率和零分率
                    long fullScoreCount = scores.stream()
                            .filter(s -> Math.abs(s.getScore() - question.getQuestionScore()) < 0.001)
                            .count();
                    long zeroScoreCount = scores.stream()
                            .filter(s -> Math.abs(s.getScore()) < 0.001)
                            .count();

                    double fullScoreRate = (double) fullScoreCount / scores.size() * 100;
                    double zeroScoreRate = (double) zeroScoreCount / scores.size() * 100;

                    questionStats.put("fullScoreRate", CommonUtils.formatNumber(fullScoreRate));
                    questionStats.put("zeroScoreRate", CommonUtils.formatNumber(zeroScoreRate));
                } else {
                    questionStats.put("difficulty", "未知");
                }

                result.add(questionStats);
            }

            return result;

        } catch (Exception e) {
            log.error("计算双向细目表失败", e);
            throw new RuntimeException("计算双向细目表失败: " + e.getMessage());
        }
    }


    public List<Map<String, Object>> calculateHomeworkSummary(Long examId, Long classId, String summaryType) {
        try {
            // 1. 获取考试详情
            ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
            if (examDetail == null) {
                throw new RuntimeException("未找到考试详情");
            }

            // 2. 获取时间范围
            LocalDateTime now = LocalDateTime.now().with(LocalTime.MAX);
            LocalDateTime startDate;
            String periodFormat = "YYYY-MM-dd";
            if ("week".equals(summaryType)) {
                // 周度：当前日期7天
                startDate = now.minusDays(6).with(LocalTime.MIN);
            } else {
                // 月度：当前日期30天
                startDate = now.minusDays(29).with(LocalTime.MIN);
            }
            // 3. 获取该时间范围内的所有考试记录
            List<ExamDetail> allExams = examDetailMapper.selectExamsByDateRange(classId, startDate, now);
            if(ObjectUtils.isEmpty(allExams)){
                return new ArrayList<>();
            }
            // 按日期分组考试记录
            Map<Long, List<ExamDetail>> groupedExams = allExams.stream().filter(e-> e.getSubjectOnlyid().equals(examDetail.getSubjectOnlyid()))
                    .collect(Collectors.groupingBy(ExamDetail::getId));
            if(ObjectUtils.isEmpty(groupedExams)){
                return new ArrayList<>();
            }
            List<Long> examIds = new ArrayList<>(groupedExams.keySet());
            // 5. 获取学生提交记录并按日期分组
            List<StudentSubmit> submits = studentSubmitMapper.selectByExamDetailIds(examIds, classId);
            // 6. 生成汇总数据
            Map<String, Object> summary = new HashMap<>();
            String formatA = startDate.format((DateTimeFormatter.ofPattern(periodFormat)));
            String formatB = now.format((DateTimeFormatter.ofPattern(periodFormat)));
            summary.put("period", formatA + "至" + formatB);
            int submitNum = submits.stream().filter(s-> s.getSubmitStatus() == 1).collect(Collectors.toList()).size();
            double submitRate = (double) submitNum / submits.size() * 100;
            summary.put("submitRate", CommonUtils.formatNumber(submitRate));
            summary.put("homeworkCount", groupedExams.size());
            List<Map<String, Object>> list = new ArrayList<>();
            list.add(summary);
            return list;

        } catch (Exception e) {
            log.error("计算作业汇总数据失败", e);
            throw new RuntimeException("计算作业汇总数据失败: " + e.getMessage());
        }
    }

    /**
     * 获取知识点映射
     */
    private List<KnowledgeMap> getKnowledgeMap(List<String> questionBankIds) {
        List<KnowledgeMap> knowledgeMaps = new ArrayList<>();
        if (questionBankIds.isEmpty()) {
            return knowledgeMaps;
        }
        try {
            ResponseEntity<Map> response = sendPost(questionBankIds);
            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                Map<String, Object> responseBody = response.getBody();
                if(ObjectUtils.isEmpty(responseBody.get("data"))){
                    return new ArrayList<>();
                }
                List<Map<String, Object>> questionDataList = (List<Map<String, Object>>) responseBody.get("data");
                for (Map<String, Object> questionData : questionDataList) {
                    List<Map<String, Object>> knowledgeList = (List<Map<String, Object>>) questionData.get("questionKnowledgeChapterRelList");
                    if (knowledgeList != null && !knowledgeList.isEmpty()) {
                        knowledgeList.forEach(stringObjectMap -> {
                            KnowledgeMap km = new KnowledgeMap();
                            km.setKnowledge(stringObjectMap.get("knowledgeName").toString());
                            km.setQuestionUuid(stringObjectMap.get("questionUuid").toString());
                            km.setQuestionParentUuid(stringObjectMap.get("questionParentUuid").toString());
                            knowledgeMaps.add(km);
                        });
                    }
                }
            }
        } catch (Exception e) {
            log.error("获取知识点映射失败: {}", e.getMessage(), e);
        }

        return knowledgeMaps;
    }
    private List<Map<String, String>> getKnowledgeList(List<String> questionBankIds) {
        List<Map<String, String>> knowledgeList = new ArrayList<>();
        if (questionBankIds.isEmpty()) {
            return knowledgeList;
        }
        try {
            ResponseEntity<Map> response = sendPost(questionBankIds);
            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                Map<String, Object> responseBody = response.getBody();
                if(ObjectUtils.isEmpty(responseBody.get("data"))){
                    return new ArrayList<>();
                }
                List<Map<String, Object>> questionDataList = (List<Map<String, Object>>) responseBody.get("data");

                if (questionDataList != null) {
                    for (Map<String, Object> questionData : questionDataList) {
                        List<Map<String, Object>> knowledgeList2 = (List<Map<String, Object>>) questionData.get("questionKnowledgeChapterRelList");
                        if (knowledgeList2 != null && !knowledgeList2.isEmpty()) {
                            knowledgeList2.forEach(stringObjectMap -> {
                                Map<String, String> knowledgeMap = new HashMap<>();
                                knowledgeMap.put("knowledgeName", stringObjectMap.get("knowledgeName").toString());
                                knowledgeMap.put("questionUuid", stringObjectMap.get("questionUuid").toString());
                                knowledgeList.add(knowledgeMap);
                            });
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("获取知识点映射失败: {}", e.getMessage(), e);
        }

        return knowledgeList;
    }

    public Map<String, Object> calculateRankChange(Long classId, Long examId) {
        Map<String, Object> result = new HashMap<>();
        List<Map<String, Object>> changes = new ArrayList<>();
        try {
            ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
            // 1. 获取最近3次考试记录
            List<ExamDetail> examRecords = examDetailMapper.selectRecentExams(classId, 3, examDetail.getSubjectOnlyid());
            if (examRecords.size() < 2) {
                return Collections.singletonMap("changes", changes);
            }

            // 2. 获取所有学生的成绩记录
            List<StudentSubmit> allSubmits = studentSubmitMapper.selectListByExamDetailIdsAndClassId(
                    examRecords.stream().map(ExamDetail::getId).collect(Collectors.toList()),
                    classId
            );

            // 3. 按学生分组
            Map<Long, List<StudentSubmit>> studentScores = allSubmits.stream()
                    .filter(ss-> ss.getSubmitStatus() == 1).collect(Collectors.groupingBy(StudentSubmit::getStudentId));

            // 4. 计算每个学生的变化情况
            for (Map.Entry<Long, List<StudentSubmit>> entry : studentScores.entrySet()) {
                List<StudentSubmit> scores = entry.getValue();

                // 至少需要2次考试记录
//                if (scores.size() < 2) continue;

                // 按考试时间降序排序
                scores.sort((a, b) -> b.getExamDetailId().compareTo(a.getExamDetailId()));

                Map<String, Object> change = new HashMap<>();
                change.put("name", scores.get(0).getStudentName());

                // 记录得分和排名
                change.put("score1", scores.get(0).getScore());
                if(scores.size() > 1 ) {
                    change.put("score2", scores.get(1).getScore());
                }else {
                    change.put("score2", 0.0);
                }
                change.put("rank1", calculateRank(allSubmits, scores.get(0)));
                if(scores.size() > 1) {
                    change.put("rank2", calculateRank(allSubmits, scores.get(1)));
                }else {
                    change.put("rank2", 0.0);
                }


                // 计算得分浮动率
                if(scores.size() > 1) {
                    double scoreFluctuation1 = calculateScoreFluctuation(
                            scores.get(0).getScore(),
                            !ObjectUtils.isEmpty(scores.get(1).getScore()) ? scores.get(1).getScore() : 0
                    );
                    change.put("scoreFluctuation1", scoreFluctuation1);
                }else {
                    change.put("scoreFluctuation1", 0.0);
                }
                // 计算排名浮动率
                int rank1 = calculateRank(allSubmits, scores.get(0));
                int rank2 = 0;
                if(scores.size() > 1) {
                    rank2 = calculateRank(allSubmits, scores.get(1));
                }
                if(rank2 == 0){
                    change.put("rankFluctuation1", 0);
                }else {
                    double rankFluctuation1 = calculateRankFluctuation(rank1, rank2);
                    change.put("rankFluctuation1", rankFluctuation1);
                }

                // 如果有第三次考试记录
                if (scores.size() >= 3) {
                    change.put("score3", scores.get(2).getScore());
                    int rank3 = calculateRank(allSubmits, scores.get(2));
                    change.put("rank3", rank3);

                    // 计算第二次到第三次的浮动率
                    double scoreFluctuation2 = calculateScoreFluctuation(
                            scores.get(1).getScore(),
                            scores.get(2).getScore()
                    );
                    change.put("scoreFluctuation2", scoreFluctuation2);

                    double rankFluctuation2 = calculateRankFluctuation(rank2, rank3);
                    change.put("rankFluctuation2", rankFluctuation2);

                    // 计算排名波动
                    double rankDeviation = calculateRankDeviation(rank1, rank2, rank3);
                    change.put("rankDeviation", rankDeviation);
                }

                // 计算得分标准差
                double scoreStdDev = calculateScoreStandardDeviation(scores);
                change.put("scoreStdDev", scoreStdDev);

                changes.add(change);
            }

            result.put("changes", changes);
            return result;
        } catch (Exception e) {
            log.error("计算成绩波动数据失败", e);
            throw new RuntimeException("计算成绩波动数据失败: " + e.getMessage());
        }
    }

    // 计算得分浮动率
    private double calculateScoreFluctuation(double score1, double score2) {
        if (score1 == 0) {
            return 0; //
        }
        double result = (score2 - score1) / score1 * 100;
        if (Double.isInfinite(result)) {
            return Double.MAX_VALUE; // 或根据业务逻辑返回其他值
        }
        return result;
    }

    // 计算排名浮动率
    private double calculateRankFluctuation(int rank1, int rank2) {
        return (rank1 - rank2) / (double) rank1 * 100;
    }

    // 计算得分标准差
    private double calculateScoreStandardDeviation(List<StudentSubmit> scores) {
        // 1. 求平均值
        double mean = scores.stream()
                .mapToDouble(StudentSubmit::getScore)
                .average()
                .orElse(0.0);

        // 2&3. 计算每次得分与平均值的差的平方
        double squareSum = scores.stream()
                .mapToDouble(s -> Math.pow(s.getScore() - mean, 2))
                .sum();  // 4. 累加

        // 5. 计算方差 = 平方差/次数
        double variance = squareSum / scores.size();

        // 6. 开根号得到标准差
        return Math.sqrt(variance);
    }

    // 计算排名波动
    private double calculateRankDeviation(int rank1, int rank2, int rank3) {
        return (Math.abs(rank2 - rank1) + Math.abs(rank3 - rank2)) / 2.0;
    }

    // 计算学生在某次考试中的排名
    private int calculateRank(List<StudentSubmit> allSubmits, StudentSubmit studentSubmit) {
        if (studentSubmit == null) return 0;

        // 获取同一次考试的所有成绩
        List<StudentSubmit> sameExamSubmits = allSubmits.stream()
                .filter(s -> s.getExamDetailId().equals(studentSubmit.getExamDetailId()))
                .collect(Collectors.toList());

        // 按分数降序排序
        sameExamSubmits.sort((a, b) -> Double.compare(b.getScore(), a.getScore()));

        // 查找当前学生的排名
        for (int i = 0; i < sameExamSubmits.size(); i++) {
            if (sameExamSubmits.get(i).getStudentId().equals(studentSubmit.getStudentId())) {
                return i + 1;  // 排名从1开始
            }
        }

        return 0;  // 未找到该学生
    }


    private double calculateStudentBlankRate(StudentSubmit submit) {
        // 获取学生的答题记录
        List<QuestionScore> questionScores = questionScoreMapper.selectBySubmitId(submit.getId());

        if (questionScores.isEmpty()) {
            return 100.0;
        }

        // 计算空白题目数量
        long blankCount = questionScores.stream()
                .filter(qs -> qs.getScore() == null || qs.getScore() == 0)
                .count();

        // 计算空白率
        return (blankCount * 100.0) / questionScores.size();
    }


    /**
     * 统计客观题答案分布
     */
    private String getObjectiveAnswerDistribution(List<QuestionScore> scores) {
        // 统计学生答案分布
        Map<String, Long> answerCounts = scores.stream()
                .collect(Collectors.groupingBy(
                        score -> score.getStudentAnswer() != null ? score.getStudentAnswer() : "-",
                        Collectors.counting()
                ));

        // 计算总人数
        long total = scores.size();

        // 格式化为: A(86.03%) B(6.88%) C(3.64%) D(3.24%) 留空占(0.2%)
        return answerCounts.entrySet().stream()
                .sorted(Map.Entry.comparingByKey())
                .map(e -> {
                    String key = e.getKey();
                    double percentage = (e.getValue() * 100.0) / total;
                    if ("".equals(key)) {
                        return String.format("留空占(%.2f%%)", percentage);
                    } else {
                        return String.format("%s占(%.2f%%)", key, percentage);
                    }
                })
                .collect(Collectors.joining(" "));
    }

    /**
     * 统计指定分数范围内的人数
     *
     * @param scores 得分列表
     * @param start  起始分数（包含）
     * @param end    结束分数（不包含，除非等于start）
     * @return 该分数范围内的人数
     */
    private long getScoreRangeCount(List<QuestionScore> scores, double start, double end) {
        return scores.stream()
                .filter(s -> {
                    double score = s.getScore();
                    if (start == end) {
                        // 如果起始分数等于结束分数，表示统计某个具体分数的人数
                        return Math.abs(score - start) < 0.0001; // 使用小数比较
                    }
                    // 否则统计区间内的人数 [start, end)
                    return score >= start && score < end;
                })
                .count();
    }


    public Map<String, Object> calculateErrorDistributionDetail(Long examId, Long classId, Long questionId) {
        try {
            log.info("获取错题分布详情 - questionId: {}", questionId);
            ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
            // 获取题目信息
            QuestionInfo questionInfo = questionInfoMapper.selectByQuestionId(questionId);

            if (questionInfo == null) {
                log.error("未找到题目信息, questionId: {}", questionId);
                throw new RuntimeException("未找到题目信息");
            }
            log.info("找到题目信息: questionId={}, questionNum={}, score={}",
                    questionInfo.getQuestionId(),
                    questionInfo.getQuestionNum(),
                    questionInfo.getQuestionScore());
            List<Map<String, Object>> questionScores = questionScoreMapper.selectQuestionScoreByExamDetail(questionInfo.getExamDetailId());
            //计算出每个学生的客观题和主观题的得分
            List<SubObjScore> subObjScores = calculateSubObjScore(questionScores);
            // 获取该题目的所有学生作答记录及其对应的学生提交信息
            List<Map<String, Object>> scoreWithSubmits = questionScoreMapper.selectScoresWithSubmitsByQuestionId(questionId);
            Double gradeScoreRate = 0.0;  //先不计算年级得分率
            //先计算年级得分率
            if(!ObjectUtils.isEmpty(classId)){
                Long gradeInfoId = classInfoMapper.selectGradeInfoIdByClassId(classId, examDetail.getId());
                double gradeAvgScore = scoreWithSubmits.stream().filter(m-> m.get("gradeInfoId").equals(gradeInfoId))
                        .mapToDouble(item -> ((Number) item.get("score")).doubleValue())
                        .average()
                        .orElse(0.0);
                gradeScoreRate = gradeAvgScore / questionInfo.getQuestionScore() * 100 ;
                //只获取班级的数据
                scoreWithSubmits = scoreWithSubmits.stream().filter(m-> m.get("classInfoId").equals(classId)).collect(Collectors.toList());
            }
            log.info("找到 {} 条作答记录", scoreWithSubmits.size());

            // 计算题目统计信息
            double avgScore = scoreWithSubmits.stream()
                    .mapToDouble(item -> ((Number) item.get("score")).doubleValue())
                    .average()
                    .orElse(0.0);

            double maxScore = scoreWithSubmits.stream()
                    .mapToDouble(item -> ((Number) item.get("score")).doubleValue())
                    .max()
                    .orElse(0.0);

            double minScore = scoreWithSubmits.stream()
                    .mapToDouble(item -> ((Number) item.get("score")).doubleValue())
                    .min()
                    .orElse(0.0);

            double scoreRate = scoreWithSubmits.isEmpty() ? 0.0 :
                    (avgScore / questionInfo.getQuestionScore()) * 100;

            Map<Integer,ScoreRange> scoreRangeList = generateScoreRanges(questionInfo.getQuestionScore());
            // 按分数段统计
            Map<String, List<Map<String, Object>>> scoreGroups = new HashMap<>();
            for (Map<String, Object> item : scoreWithSubmits) {
                Double score = ((Number) item.get("score")).doubleValue();
                log.info("错题信息：" + item.get("score") +"----"+ item.get("questionId") );
                String scoreRange;
                if(questionInfo.getIsSubjectiveItem() == 0){
                    scoreRange = item.get("studentAnswer").toString();
                }else {
                    if(score.equals(questionInfo.getQuestionScore())){
                        scoreRange = String.format("[%s]", score.intValue());
                    }else {
                        int i;
                        int result;
                        if(questionInfo.getQuestionScore() < 5){
                            if(score == 0){
                                i = 0;
                            }else {
                                i = score.intValue() - 1;
                            }
                            result = i;
                        }else {
                            i = (int) (score / questionInfo.getQuestionScore() * 100);
                            if(scoreRangeList.size() < 4){
                                if(i >= 0 && i < 40){
                                    result = 0;
                                }else if(i>=40 && i < 80){
                                    result = 1;
                                }else {
                                    result = 2;
                                }
                            }else {
                                if (i <= 25) {
                                    result = 0;
                                } else if (i <= 50) {
                                    result = 1;
                                } else if (i <= 75) {
                                    result = 2;
                                } else {
                                    result = 3;
                                }
                            }
                        }
                        ScoreRange sr;
                        if(result >= scoreRangeList.size()){
                            sr = scoreRangeList.get(scoreRangeList.size() -1);
                        }else {
                            sr = scoreRangeList.get(result);
                        }
                        scoreRange = String.format("%s,%s", sr.getStart(), sr.getEnd());
                    }
                }
                scoreGroups.computeIfAbsent(scoreRange, k2-> new ArrayList<>()).add(item);
            }
            // 格式化返回数据
            List<Map<String, Object>> details = new ArrayList<>();
            for (Map.Entry<String, List<Map<String, Object>>> entry : scoreGroups.entrySet()) {
                Map<String, Object> detail = new HashMap<>();
                detail.put("scoreRange", entry.getKey());
                detail.put("students", entry.getValue().stream()
                        .map(item -> {
                            Map<String, Object> studentInfo = new HashMap<>();
                            if(questionInfo.getIsSubjectiveItem() == 0) {
                                studentInfo.put("name", String.format("%s",
                                        item.get("studentName")));
                            }else {
                                List<SubObjScore> studentScore = subObjScores.stream().filter(s->s.getSubmitId().equals(item.get("submitId"))).collect(Collectors.toList());
                                double subScore = 0.0;
                                if(!studentScore.isEmpty()){
                                    subScore = studentScore.get(0).getSubScore();
                                }
                                studentInfo.put("name", String.format("%s(%s/%s)",
                                        item.get("studentName"),
                                        item.get("score"),
                                        subScore));
                            }
                            studentInfo.put("paperImages", JSON.parseArray(item.get("paperImages").toString(), PaperImage.class));
                            return studentInfo;
                        })
                        .collect(Collectors.toList()));
                detail.put("count", entry.getValue().size());
                detail.put("percentage", String.format("%.2f",
                        (entry.getValue().size() * 100.0) / scoreWithSubmits.size()));

                details.add(detail);
            }
            details = details.stream()
                    .sorted(Comparator.comparing(
                            map -> extractStartNumber((String) map.get("scoreRange"))
                    ))
                    .collect(Collectors.toList());
            Map<String, Object> result = new HashMap<>();
            Map<String, Object> questionInfoMap = new HashMap<>();
            questionInfoMap.put("x", questionInfo.getX());
            questionInfoMap.put("y", questionInfo.getY());
            questionInfoMap.put("w", questionInfo.getW());
            questionInfoMap.put("h", questionInfo.getH());
            questionInfoMap.put("page", questionInfo.getPage());
            questionInfoMap.put("fullScore", questionInfo.getQuestionScore());
            questionInfoMap.put("avgScore", String.format("%.2f", avgScore));
            questionInfoMap.put("answer", questionInfo.getQuestionAnswer() != null && !questionInfo.getQuestionAnswer().isEmpty()
                    ? questionInfo.getQuestionAnswer() : "-");
            questionInfoMap.put("maxScore", maxScore);
            questionInfoMap.put("minScore", minScore);
            if(questionInfo.getIsSubjectiveItem() == 0){
                List<Map<String, Object>> rightRate = details.stream().filter(d-> d.get("scoreRange").equals(questionInfo.getQuestionAnswer())).collect(Collectors.toList());
                if(!rightRate.isEmpty()){
                    questionInfoMap.put("scoreRate", rightRate.get(0).get("percentage"));
                }else {
                    questionInfoMap.put("scoreRate", 0.0);
                }
            }else {
                questionInfoMap.put("scoreRate", String.format("%.2f", scoreRate));
            }
            questionInfoMap.put("examScoreRate", String.format("%.2f", gradeScoreRate));
            result.put("questionInfo", questionInfoMap);
            result.put("details", details);
            return result;
        } catch (Exception e) {
            log.error("计算错题分布详情失败", e);
            throw new RuntimeException("计算错题分布详情失败: " + e.getMessage());
        }
    }

    private List<SubObjScore> calculateSubObjScore(List<Map<String, Object>> questionScores) {
        if (questionScores == null || questionScores.isEmpty()) {
            return Collections.emptyList();
        }

        // 首先按submitId分组，再按isSubjectiveItem分组，计算各组得分
        Map<Long, Map<Integer, Double>> submitScoreMap = questionScores.stream()
                .collect(Collectors.groupingBy(
                        // 一级分组：按submitId分组
                        submit -> (Long) submit.get("submitId"),
                        // 二级分组：按isSubjectiveItem分组，并计算该组得分总和
                        Collectors.groupingBy(
                                submit -> (Integer) submit.get("isSubjectiveItem"),
                                Collectors.summingDouble(submit -> Double.parseDouble(submit.get("score").toString()))
                        )
                ));

        // 将分组结果转换为SubObjScore列表
        return submitScoreMap.entrySet().stream()
                .map(entry -> {
                    Long submitId = Long.valueOf(entry.getKey());
                    Map<Integer, Double> scoreMap = entry.getValue();

                    // 获取客观题得分（isSubjectiveItem=0）
                    double objectiveScore = scoreMap.getOrDefault(0, 0.0);
                    // 获取主观题得分（isSubjectiveItem=1）
                    double subjectiveScore = scoreMap.getOrDefault(1, 0.0);

                    return new SubObjScore(submitId, objectiveScore, subjectiveScore);
                })
                .collect(Collectors.toList());
    }

    private static int extractStartNumber(String scoreRange) {
        Pattern pattern = Pattern.compile("\\d+");
        Matcher matcher = pattern.matcher(scoreRange);
        if (matcher.find()) {
            log.info("" + Integer.parseInt(matcher.group()));
            return Integer.parseInt(matcher.group());
        }
        return 0; // 若格式异常，默认返回 0
    }

    public List<Map<String, Object>> calculateErrorDistributionDetailList(Long examId, Long classId, Integer rateLeft, Integer rateRight, String questionTypeName) {
        if(ObjectUtils.isEmpty(rateLeft)){
            rateLeft = 0;
        }
        if(ObjectUtils.isEmpty(rateRight)){
            rateRight = 100;
        }
        try {
            log.info("获取错题分布详情 - examDetail: {}", classId);
            ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
            // 获取题目信息
            List<QuestionInfo> questionInfos = questionInfoMapper.selectByExamDetailId(examDetail.getId());

            if (questionInfos == null) {
                log.error("未找到题目信息, examDetailId: {}", examDetail.getId());
                throw new RuntimeException("未找到题目信息");
            }
            log.info("找到题目信息: examId={}", examId);
            List<Long> questionIds = questionInfos.stream().map(QuestionInfo::getQuestionId).collect(Collectors.toList());
            // 获取该题目的所有学生作答记录及其对应的学生提交信息
            List<Map<String, Object>> scoreWithSubmitsMap = questionScoreMapper.selectScoresWithSubmitsByQuestionIds(questionIds);
            //按照 题目的id分组
            Map<Long, List<Map<String, Object>>> mapList = scoreWithSubmitsMap.stream()
                    .collect(Collectors.groupingBy(map -> (Long) map.get("questionId")));
            List<Map<String, Object>> resultList = new ArrayList<>();
            mapList.forEach((k, v) -> {
                List<Map<String, Object>> scoreWithSubmits = v;
                QuestionInfo questionInfo = questionInfos.stream().filter(q -> q.getQuestionId().equals(k)).findFirst().get();
                //计算下年级得分率
                double examAvgScore = scoreWithSubmits.stream()
                        .mapToDouble(item -> ((Number) item.get("score")).doubleValue())
                        .average()
                        .orElse(0.0);
                double examScoreRate = scoreWithSubmits.isEmpty() ? 0.0 :
                        (examAvgScore / questionInfo.getQuestionScore()) * 100;
                if(!ObjectUtils.isEmpty(classId)){
                    //只获取班级的数据
                    scoreWithSubmits = scoreWithSubmits.stream().filter(m-> m.get("classInfoId").equals(classId)).collect(Collectors.toList());
                }
                log.info("找到 {} 条作答记录", scoreWithSubmits.size());

                // 计算题目统计信息
                double avgScore = scoreWithSubmits.stream()
                        .mapToDouble(item -> ((Number) item.get("score")).doubleValue())
                        .average()
                        .orElse(0.0);
                double scoreRate = scoreWithSubmits.isEmpty() ? 0.0 :
                        (avgScore / questionInfo.getQuestionScore()) * 100;

                double maxScore = scoreWithSubmits.stream()
                        .mapToDouble(item -> ((Number) item.get("score")).doubleValue())
                        .max()
                        .orElse(0.0);

                double minScore = scoreWithSubmits.stream()
                        .mapToDouble(item -> ((Number) item.get("score")).doubleValue())
                        .min()
                        .orElse(0.0);
                Map<Integer,ScoreRange> scoreRangeList = generateScoreRanges(questionInfo.getQuestionScore());
                // 按分数段统计
                Map<String, List<Map<String, Object>>> scoreGroups = new HashMap<>();
                for (Map<String, Object> item : scoreWithSubmits) {
                    log.info("错题信息：" + item.get("score") +"----"+ item.get("questionId") );
                    Double score = ((Number) item.get("score")).doubleValue();
                    String scoreRange;
                    if(questionInfo.getIsSubjectiveItem() == 0){
                        scoreRange = item.get("studentAnswer").toString();
                    }else {
                        if(score.equals(questionInfo.getQuestionScore())){
                            scoreRange = String.format("[%s]", score.intValue());
                        }else {
                            int i;
                            int result;
                            if(questionInfo.getQuestionScore() < 5){
                                if(score == 0){
                                    i = 0;
                                }else {
                                    i = score.intValue() - 1;
                                }
                                result = i;
                            }else {
                                i = (int) (score / questionInfo.getQuestionScore() * 100);
                                if(scoreRangeList.size() < 4){
                                    if(i >= 0 && i < 40){
                                        result = 0;
                                    }else if(i>=40 && i < 80){
                                        result = 1;
                                    }else {
                                        result = 2;
                                    }
                                }else {
                                    if (i <= 25) {
                                        result = 0;
                                    } else if (i <= 50) {
                                        result = 1;
                                    } else if (i <= 75) {
                                        result = 2;
                                    } else {
                                        result = 3;
                                    }
                                }
                            }
                            ScoreRange sr;
                            if(result >= scoreRangeList.size()){
                                sr = scoreRangeList.get(scoreRangeList.size() -1);
                            }else {
                                sr = scoreRangeList.get(result);
                            }
                            scoreRange = String.format("%s,%s", sr.getStart(), sr.getEnd());

                        }
                    }
                    scoreGroups.computeIfAbsent(scoreRange, k2-> new ArrayList<>()).add(item);
                }

                // 格式化返回数据
                List<Map<String, Object>> details = new ArrayList<>();
                for (Map.Entry<String, List<Map<String, Object>>> entry : scoreGroups.entrySet()) {
                    Map<String, Object> detail = new HashMap<>();
                    String scoreRange = entry.getKey();
                    if(scoreRange.isEmpty()){
                        scoreRange = "空";
                    }
                    detail.put("scoreRange", scoreRange);
                    detail.put("students", entry.getValue().stream()
                            .map(item -> {
                                Map<String, Object> studentInfo = new HashMap<>();
                                studentInfo.put("name", String.format("%s(%s/%s)",
                                        item.get("studentName"),
                                        item.get("score"),
                                        item.get("totalScore")));
                                studentInfo.put("paperImages", item.get("paperImages"));
                                return studentInfo;
                            })
                            .collect(Collectors.toList()));
                    detail.put("count", entry.getValue().size());
                    detail.put("percentage", String.format("%.2f",
                            (entry.getValue().size() * 100.0) / scoreWithSubmits.size()));
                    details.add(detail);
                }
                details = details.stream()
                        .sorted(Comparator.comparing(
                                map -> extractStartNumber((String) map.get("scoreRange"))
                        ))
                        .collect(Collectors.toList());
                Map<String, Object> result = new HashMap<>();
                Map<String, Object> questionInfoMap = new HashMap<>();
                questionInfoMap.put("fullScore", questionInfo.getQuestionScore());
                questionInfoMap.put("examScoreRate", String.format("%.2f", examScoreRate));
                questionInfoMap.put("avgScore", String.format("%.2f", avgScore));
                questionInfoMap.put("maxScore", maxScore);
                questionInfoMap.put("minScore", minScore);
                if(questionInfo.getIsSubjectiveItem() == 0){
                    List<Map<String, Object>> rightRate = details.stream().filter(d-> d.get("scoreRange").equals(questionInfo.getQuestionAnswer())).collect(Collectors.toList());
                    if(!rightRate.isEmpty()){
                        questionInfoMap.put("scoreRate", rightRate.get(0).get("percentage"));
                    }else {
                        questionInfoMap.put("scoreRate", 0.0);
                    }
                }else {
                    questionInfoMap.put("scoreRate", String.format("%.2f", scoreRate));
                }
                //questionInfoMap.put("gradeScoreRate", String.format("%.2f", gradeScoreRate));
                result.put("questionInfo", questionInfoMap);
                result.put("details", details);
                result.put("questionId", questionInfo.getQuestionId());
                result.put("questionTypeName", questionInfo.getQuestionTypeName());
                result.put("questionUUid", questionInfo.getQuestionBankId());
                result.put("isSubjectiveItem", questionInfo.getIsSubjectiveItem());
                result.put("scoreRate", String.format("%.2f", scoreRate));
                if(!ObjectUtils.isEmpty(questionInfo.getQuestionAlias())){
                    result.put("questionNum", questionInfo.getQuestionTypeName() + "-" + questionInfo.getQuestionAlias());
                }else {
                    int bigQuestionNum = CalculateQuestionNumUtil.bigQuestionNum(questionInfo.getQuestionNum());
                    int smallQuestionNum = CalculateQuestionNumUtil.smallQuestionNum(questionInfo.getQuestionNum());
                    if (smallQuestionNum != 0) {
                        result.put("questionNum", bigQuestionNum + "-" + questionInfo.getQuestionTypeName() + "-" + smallQuestionNum);
                    } else {
                        result.put("questionNum", questionInfo.getQuestionTypeName() + "-" + bigQuestionNum);
                    }
                }
                resultList.add(result);
            });
            Integer finalRateLeft = rateLeft;
            Integer finalRateRight = rateRight;
            List<Map<String, Object>> filteredList = resultList.stream()
                    .filter(result -> {
                        // 处理 scoreRate 过滤条件
                        Map<String, Object> questionInfoMap = (Map<String, Object>) result.get("questionInfo");
                        log.info("分数：" + questionInfoMap.get("scoreRate"));
                        String scoreRateStr = String.valueOf(questionInfoMap.get("scoreRate"));
                        double scoreRate = Double.parseDouble(scoreRateStr);
                        boolean scoreCondition = scoreRate >= finalRateLeft.doubleValue() && scoreRate <= finalRateRight;
                        // 处理 questionTypeName 过滤条件
                        boolean typeCondition = true;
                        if (questionTypeName != null && !questionTypeName.isEmpty()) {
                            typeCondition = questionTypeName.equals(result.get("questionTypeName"));
                        }

                        return scoreCondition && typeCondition;
                    })
                    .collect(Collectors.toList());
            filteredList = filteredList.stream()
                    .sorted(Comparator.comparing(
                            map -> (Long)map.get("questionId")
                    ))
                    .collect(Collectors.toList());
            return filteredList;
        } catch (Exception e) {
            log.error("计算错题分布详情失败", e);
            throw new RuntimeException("计算错题分布详情失败: " + e.getMessage());
        }
    }

    /**
     * 计算题目难度分布
     * 难度系数 = 平均得分 / 满分
     * 难度系数越高，题目越简单
     * <0.3 难题
     * 0.3-0.7 中等
     * >0.7 容易
     */
    private String calculateQuestionDifficultyDistribution(List<StudentSubmit> submits) {
        if (submits == null || submits.isEmpty()) {
            return "无数据";
        }

        try {
            // 获取考试详情ID
            Long examDetailId = submits.get(0).getExamDetailId();

            // 获取所有题目信息
            List<QuestionInfo> questions = questionInfoMapper.selectByExamDetailId(examDetailId);
            Map<Long, QuestionInfo> questionInfoMap = questions.stream()
                    .collect(Collectors.toMap(QuestionInfo::getQuestionId, q -> q));

            // 获取所有提交ID
            List<Long> submitIds = submits.stream()
                    .map(StudentSubmit::getId)
                    .collect(Collectors.toList());

            // 批量获取所有题目得分
            Map<Long, List<QuestionScore>> questionScoresMap = new HashMap<>();
            if (!submitIds.isEmpty()) {
                List<QuestionScore> allScores = questionScoreMapper.selectByStudentSubmitIds(submitIds);
                questionScoresMap = allScores.stream()
                        .collect(Collectors.groupingBy(QuestionScore::getQuestionId));
            }

            // 统计各难度等级的题目
            Map<String, List<String>> difficultyGroups = new HashMap<>();
            difficultyGroups.put("较易", new ArrayList<>());  // >0.7
            difficultyGroups.put("一般", new ArrayList<>());  // 0.3-0.7
            difficultyGroups.put("较难", new ArrayList<>());  // <0.3
            difficultyGroups.put("困难", new ArrayList<>());
            difficultyGroups.put("简单", new ArrayList<>());
            // 计算每道题的难度系数
            for (QuestionInfo question : questions) {
                List<QuestionScore> scores = questionScoresMap.getOrDefault(question.getQuestionId(), Collections.emptyList());
                if (scores.isEmpty() || question.getQuestionScore() == 0) {
                    continue;
                }

                // 计算平均分
                double avgScore = scores.stream()
                        .mapToDouble(QuestionScore::getScore)
                        .average()
                        .orElse(0.0);

                // 计算难度系数 = 平均分/满分
                String questionLabel;
                double difficultyIndex = avgScore / question.getQuestionScore();
                int bigQuestionNum = CalculateQuestionNumUtil.bigQuestionNum(question.getQuestionNum());
                int smallQuestionNum = CalculateQuestionNumUtil.smallQuestionNum(question.getQuestionNum());
                if(smallQuestionNum != 0) {
                    questionLabel = bigQuestionNum +"-"+ question.getQuestionTypeName() +"-"+ smallQuestionNum;
                }else {
                    questionLabel = question.getQuestionTypeName() +"-"+ bigQuestionNum;
                }
                // 根据难度系数分类
                if (difficultyIndex <= 0.2) {
                    difficultyGroups.get("困难").add(questionLabel);
                }  else if (difficultyIndex > 0.2 && difficultyIndex <= 0.4) {
                    difficultyGroups.get("较难").add(questionLabel);
                } else if (difficultyIndex > 0.4 && difficultyIndex <= 0.6) {
                    difficultyGroups.get("一般").add(questionLabel);
                } else if (difficultyIndex > 0.6 && difficultyIndex <= 0.8) {
                    difficultyGroups.get("较易").add(questionLabel);
                } else {
                    difficultyGroups.get("简单").add(questionLabel);
                }
            }

            // 格式化输出
            StringBuilder result = new StringBuilder();

            // 较易题目 (>0.7)
            if (!difficultyGroups.get("简单").isEmpty()) {
                result.append("简单题目 (>0.8)：")
                        .append(String.join("、", difficultyGroups.get("简单"))).append(";");
            }
            if (!difficultyGroups.get("较易").isEmpty()) {
                result.append("(0.8<)较易题目 (>0.6)：")
                        .append(String.join("、", difficultyGroups.get("较易"))).append(";");
            }
            if (!difficultyGroups.get("一般").isEmpty()) {
                result.append("(0.6<)一般题目 (>0.4)：")
                        .append(String.join("、", difficultyGroups.get("一般"))).append(";");
            }
            if (!difficultyGroups.get("较难").isEmpty()) {
                result.append("(0.4<)较难题目(>0.2)：")
                        .append(String.join("、", difficultyGroups.get("较难"))).append(";");
            }
            // 较难题目 (<0.3)
            if (!difficultyGroups.get("困难").isEmpty()) {
                if (result.length() > 0) result.append(" ");
                result.append("困难题目(<0.2)：")
                        .append(String.join("、", difficultyGroups.get("困难"))).append(";");
            }

            return result.length() > 0 ? result.toString() : "无数据";

        } catch (Exception e) {
            log.error("计算题目难度分布失败", e);
            return "计算失败";
        }
    }

    /**
     * 计算分半信度
     * 1. 将整个考试按主观题和客观题分成两个部分
     * 2. 对于每个学生，计算他们在每个部分的得分
     * 3. 计算两部分得分的相关系数
     * 4. 使用Spearman-Brown公式校正
     */
    private double calculateSplitHalfReliability(List<StudentSubmit> submits) {
        if (submits == null || submits.isEmpty()) {
            return 0.0;
        }

        try {
            // 获取考试详情ID
            Long examDetailId = submits.get(0).getExamDetailId();

            // 获取所有题目信息
            List<QuestionInfo> questions = questionInfoMapper.selectByExamDetailId(examDetailId);
            if (questions.isEmpty()) {
                return 0.0;
            }

            // 获取所有提交ID
            List<Long> submitIds = submits.stream()
                    .map(StudentSubmit::getId)
                    .collect(Collectors.toList());

            // 批量获取所有题目得分
            List<QuestionScore> allScores = new ArrayList<>();
            if (!submitIds.isEmpty()) {
                allScores = questionScoreMapper.selectByStudentSubmitIds(submitIds);
            }

            // 按学生ID分组的得分
            Map<Long, List<QuestionScore>> scoresByStudent = allScores.stream()
                    .collect(Collectors.groupingBy(qs -> qs.getStudentSubmitId()));

            // 计算每个学生的主客观题得分
            List<Double> objectiveScores = new ArrayList<>();
            List<Double> subjectiveScores = new ArrayList<>();

            for (StudentSubmit submit : submits) {
                List<QuestionScore> studentScores = scoresByStudent.getOrDefault(submit.getId(), Collections.emptyList());

                // 计算主观题总分
                double subjectiveTotal = studentScores.stream()
                        .filter(qs -> {
                            QuestionInfo qi = questions.stream()
                                    .filter(q -> q.getQuestionId().equals(qs.getQuestionId()))
                                    .findFirst()
                                    .orElse(null);
                            //return qi != null && qi.getIsSubjectiveItem() == 1;
                            return qi != null && isEven(qi.getQuestionNum());
                        })
                        .mapToDouble(QuestionScore::getScore)
                        .sum();

                // 计算客观题总分
                double objectiveTotal = studentScores.stream()
                        .filter(qs -> {
                            QuestionInfo qi = questions.stream()
                                    .filter(q -> q.getQuestionId().equals(qs.getQuestionId()))
                                    .findFirst()
                                    .orElse(null);
                            //return qi != null && qi.getIsSubjectiveItem() == 0;
                            return qi != null && !isEven(qi.getQuestionNum());
                        })
                        .mapToDouble(QuestionScore::getScore)
                        .sum();

                objectiveScores.add(objectiveTotal);
                subjectiveScores.add(subjectiveTotal);
            }

            // 计算相关系数
            double correlation = calculateCorrelation(objectiveScores, subjectiveScores, submitIds);

            // 使用Spearman-Brown公式校正
            // 校正公式：2r/(1+r)，其中r为相关系数
            double r = (2 * correlation) / (1 + correlation);
            r = BigDecimalFormat(String.valueOf(r));
            return r;

        } catch (Exception e) {
            log.error("计算分半信度失败", e);
            return 0.0;
        }
    }

    //判断奇数偶数
    public static boolean isEven(int number) {
        return number % 2 == 0;
    }

    public static double BigDecimalFormat(String value) {
        if (value == null || !value.matches("-?\\d+(\\.\\d+)?")) { // 简单的正则表达式用于匹配整数和小数
            // 如果输入无效，返回默认值或抛出自定义异常等
            // 在这里我们选择返回0作为默认值
            return 0.0;
        }

        // 输入有效，继续处理
        try {
            BigDecimal bd = new BigDecimal(value);
            bd = bd.setScale(2, RoundingMode.HALF_UP);
            return bd.doubleValue();
        } catch (NumberFormatException e) {
            // 处理可能的异常情况，比如数值超出范围等
            return 0.0; // 或者采取其他措施，例如记录日志、抛出自定义异常等
        }
    }
    /**
     * 计算区分度指数
     * 1. 按总分排序，取前27%为高分组，后27%为低分组
     * 2. 计算高低组平均分
     * 3. 区分度 = (高分组平均分 - 低分组平均分) / 标准差
     * <p>
     * 区分度评价标准：
     * >0.4：区分度很好
     * 0.3-0.39：区分度较好
     * 0.2-0.29：区分度不太好，需要修改
     * <0.2：区分度差，建议淘汰
     */
    private double calculateDiscriminationIndex(List<StudentSubmit> submits, Integer fullScore) {
        if (submits == null || submits.size() < 2) {
            return 0.0;
        }

        try {
            // 1. 按总分排序
            List<StudentSubmit> sortedSubmits = new ArrayList<>(submits);
            sortedSubmits.sort((a, b) -> Double.compare(b.getScore(), a.getScore()));

            // 2. 取27%为高分组和低分组
            int groupSize = Math.max(1, (int) (submits.size() * 0.27));
            List<StudentSubmit> highGroup = sortedSubmits.subList(0, groupSize);
            List<StudentSubmit> lowGroup = sortedSubmits.subList(sortedSubmits.size() - groupSize, sortedSubmits.size());

            // 3. 计算高低组平均分
            double highAvg = highGroup.stream()
                    .mapToDouble(StudentSubmit::getScore)
                    .average()
                    .orElse(0.0);

            double lowAvg = lowGroup.stream()
                    .mapToDouble(StudentSubmit::getScore)
                    .average()
                    .orElse(0.0);

//            // 4. 计算总体标准差
//            double standardDeviation = calculateStandardDeviation(submits, StudentSubmit::getScore);
//            if (standardDeviation == 0) {
//                return 0.0;
//            }

            // 5. 计算区分度
            return (highAvg - lowAvg) / fullScore;

        } catch (Exception e) {
            log.error("计算区分度失败", e);
            return 0.0;
        }
    }

    /**
     * 计算题目区分度分布
     */
    private String calculateQuestionDiscriminationDistribution(List<StudentSubmit> submits) {
        if (submits == null || submits.isEmpty()) {
            return "无数据";
        }

        try {
            // 获取考试详情ID
            Long examDetailId = submits.get(0).getExamDetailId();

            // 获取所有题目信息
            List<QuestionInfo> questions = questionInfoMapper.selectByExamDetailId(examDetailId);
            Map<Long, QuestionInfo> questionInfoMap = questions.stream()
                    .collect(Collectors.toMap(QuestionInfo::getQuestionId, q -> q));

            // 获取所有提交ID
            List<Long> submitIds = submits.stream()
                    .map(StudentSubmit::getId)
                    .collect(Collectors.toList());

            // 批量获取所有题目得分
            Map<Long, List<QuestionScore>> questionScoresMap = new HashMap<>();
            if (!submitIds.isEmpty()) {
                List<QuestionScore> allScores = questionScoreMapper.selectByStudentSubmitIds(submitIds);
                questionScoresMap = allScores.stream()
                        .collect(Collectors.groupingBy(QuestionScore::getQuestionId));
            }

            // 统计各区分度等级的题目
            Map<String, List<String>> discriminationGroups = new HashMap<>();
            discriminationGroups.put("优秀", new ArrayList<>());  // >0.4
            discriminationGroups.put("良好", new ArrayList<>());  // 0.3-0.39
            discriminationGroups.put("一般", new ArrayList<>());  // 0.2-0.29
            discriminationGroups.put("较差", new ArrayList<>());  // <0.2

            // 计算每道题的区分度
            for (QuestionInfo question : questions) {
                List<QuestionScore> scores = questionScoresMap.getOrDefault(question.getQuestionId(), Collections.emptyList());
                if (scores.isEmpty()) {
                    continue;
                }

                // 按得分排序
                List<QuestionScore> sortedScores = new ArrayList<>(scores);
                sortedScores.sort((a, b) -> Double.compare(b.getScore(), a.getScore()));

                // 计算高低组平均分
                int groupSize = Math.max(1, (int) (scores.size() * 0.27));
                double highAvg = sortedScores.subList(0, groupSize).stream()
                        .mapToDouble(QuestionScore::getScore)
                        .average()
                        .orElse(0.0);
                double lowAvg = sortedScores.subList(scores.size() - groupSize, scores.size()).stream()
                        .mapToDouble(QuestionScore::getScore)
                        .average()
                        .orElse(0.0);

                // 计算标准差
                double sd = calculateStandardDeviation(scores, QuestionScore::getScore);
                if (sd == 0) continue;

                // 计算区分度
                double discrimination = (highAvg - lowAvg) / sd;
                String questionLabel;
                int bigQuestionNum = CalculateQuestionNumUtil.bigQuestionNum(question.getQuestionNum());
                int smallQuestionNum = CalculateQuestionNumUtil.smallQuestionNum(question.getQuestionNum());
                if(smallQuestionNum != 0) {
                    questionLabel = bigQuestionNum +"-"+ question.getQuestionTypeName() +"-"+ smallQuestionNum;
                }else {
                    questionLabel = question.getQuestionTypeName() +"-"+ bigQuestionNum;
                }
                // 根据区分度分类
                if (discrimination >= 0.4) {
                    discriminationGroups.get("优秀").add(questionLabel);
                } else if (discrimination >= 0.3) {
                    discriminationGroups.get("良好").add(questionLabel);
                } else if (discrimination >= 0.2) {
                    discriminationGroups.get("一般").add(questionLabel);
                } else {
                    discriminationGroups.get("较差").add(questionLabel);
                }
            }

            // 格式化输出
            StringBuilder result = new StringBuilder();

            // 优秀题目 (>0.4)
            if (!discriminationGroups.get("优秀").isEmpty()) {
                result.append("优秀题目 (>0.4)：")
                        .append(String.join("、", discriminationGroups.get("优秀")));
            }

            // 良好题目 (0.3-0.39)
            if (!discriminationGroups.get("良好").isEmpty()) {
                if (result.length() > 0) result.append(" ");
                result.append("良好题目 (0.3~0.39)：")
                        .append(String.join("、", discriminationGroups.get("良好")));
            }

            // 一般题目 (0.2-0.29)
            if (!discriminationGroups.get("一般").isEmpty()) {
                if (result.length() > 0) result.append(" ");
                result.append("一般题目 (0.2~0.29)：")
                        .append(String.join("、", discriminationGroups.get("一般")));
            }

            // 较差题目 (<0.2)
            if (!discriminationGroups.get("较差").isEmpty()) {
                if (result.length() > 0) result.append(" ");
                result.append("较差题目 (<0.2)：")
                        .append(String.join("、", discriminationGroups.get("较差")));
            }

            return result.length() > 0 ? result.toString() : "无数据";

        } catch (Exception e) {
            log.error("计算题目区分度分布失败", e);
            return "计算失败";
        }
    }

    /**
     * 计算标准差
     *
     * @param scores      分数列表
     * @param scoreGetter 获取分数的函数
     */
    private <T> double calculateStandardDeviation(List<T> scores, Function<T, Double> scoreGetter) {
        if (scores == null || scores.isEmpty()) {
            return 0.0;
        }

        double mean = scores.stream()
                .mapToDouble(s -> scoreGetter.apply(s))
                .average()
                .orElse(0.0);

        double variance = scores.stream()
                .mapToDouble(s -> Math.pow(scoreGetter.apply(s) - mean, 2))
                .average()
                .orElse(0.0);

        return Math.sqrt(variance);
    }

    private Map<String, Object> calculateSummary(List<Map<String, Object>> scoreData) {
        Map<String, Object> summary = new HashMap<>();

        if (scoreData == null || scoreData.isEmpty()) {
            return summary;
        }

        // 计算提交人数和总人数
        int totalStudents = scoreData.size();
        long submittedCount = scoreData.stream()
                .filter(score -> score.get("score") != null)
                .count();

        // 计算提交率
        double submitRate = (double) submittedCount / totalStudents * 100;
        summary.put("submitRate", String.format("%.1f", submitRate));

        // 计算平均分
        OptionalDouble avgScore = scoreData.stream()
                .filter(score -> score.get("score") != null)
                .mapToDouble(score -> Double.parseDouble(score.get("score").toString()))
                .average();
        summary.put("avgScore", String.format("%.1f", avgScore.orElse(0.0)));

        // 计算最高分和最低分
        OptionalDouble maxScore = scoreData.stream()
                .filter(score -> score.get("score") != null)
                .mapToDouble(score -> Double.parseDouble(score.get("score").toString()))
                .max();
        OptionalDouble minScore = scoreData.stream()
                .filter(score -> score.get("score") != null)
                .mapToDouble(score -> Double.parseDouble(score.get("score").toString()))
                .min();

        summary.put("maxScore", String.format("%.1f", maxScore.orElse(0.0)));
        summary.put("minScore", String.format("%.1f", minScore.orElse(0.0)));

        // 统计错题知识点
        Set<String> wrongKnowledgePoints = new HashSet<>();
        scoreData.stream()
                .filter(score -> score.get("score") != null &&
                        Double.parseDouble(score.get("score").toString()) < 60.0)
                .forEach(score -> {
                    if (score.get("questionStats") != null) {
                        List<Map<String, Object>> questions = (List<Map<String, Object>>) score.get("questionStats");
                        questions.stream()
                                .filter(q -> q.get("correct") != null && !(Boolean) q.get("correct"))
                                .forEach(q -> {
                                    if (q.get("knowledge") != null) {
                                        wrongKnowledgePoints.add(q.get("knowledge").toString());
                                    }
                                });
                    }
                });

        String wrongKnowledgePointsStr = String.join("、", wrongKnowledgePoints);
        summary.put("wrongKnowledgePoints", wrongKnowledgePointsStr);

        // 作业次数
        summary.put("homeworkCount", scoreData.size());

        return summary;
    }

    public static Map<Integer,ScoreRange> generateScoreRanges(double score) {
        Map<Integer,ScoreRange> ranges = new HashMap<>();
        if(score <5){
            int x = 1;
            for(int i2 = 0 ; i2< score; i2++){
                int p = i2 * x;
                int o = p + x;
                ScoreRange range = new ScoreRange();
                range.setStart("[" + p);
                range.setEnd(o + ")");
                ranges.put(i2,range);
            }
        }else {
            int x = (int) Math.ceil(score / 4);
            for(int i2 = 0; i2 < score/x; i2++){
                int p = i2 * x;
                int o = p + x;
                if(o > score){
                    o = (int) score;
                }
                ScoreRange range = new ScoreRange();
                range.setStart("[" + p);
                range.setEnd(o + ")");
                ranges.put(i2,range);
            }
        }
        return ranges;
    }

    public List<Map<String, Object>> calculateKnowledgeScoreRatesByGrade(Long examId, List<Long> classIds) {
        try {
            // 1. 获取考试详情
            ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
            if (examDetail == null) {
                throw new RuntimeException("未找到考试详情");
            }

            // 如果classIds为空，获取该考试的所有班级
            if (ObjectUtils.isEmpty(classIds)) {
                List<ClassInfo> allClassInfos = classInfoMapper.selectByExamDetailId(examDetail.getId());
                classIds = allClassInfos.stream()
                        .map(ClassInfo::getClassId)
                        .collect(Collectors.toList());
            }

            // 2. 获取班级信息
            List<ClassInfo> classInfos = classInfoMapper.selectByClassIds(classIds);
            classInfos = classInfos.stream().filter(c -> c.getExamDetailId().equals(examDetail.getId())).collect(Collectors.toList());
            // 3. 获取所有学生提交记录
            List<StudentSubmit> allSubmits = studentSubmitMapper.selectByExamDetailIdsAndClassIds(
                    Collections.singletonList(examDetail.getId()), classIds);
            if (allSubmits.isEmpty()) {
                throw new RuntimeException("未找到提交信息");
            }
            // 4. 获取题目得分情况
            List<Long> submitIds = allSubmits.stream().map(StudentSubmit::getId).collect(Collectors.toList())
                    .stream().distinct().collect(Collectors.toList());
            List<QuestionScore> allScores = questionScoreMapper.selectByStudentSubmitIds(submitIds);

            // 5. 获取题目信息
            List<Long> questionIds = allScores.stream().map(QuestionScore::getQuestionId).collect(Collectors.toList()).stream().distinct()
                    .collect(Collectors.toList());
            List<QuestionInfo> questions = questionInfoMapper.selectListByQuestionIds(questionIds);
            // 6. 获取知识点映射
            List<String> questionBankIds = questions.stream()
                    .map(q -> q.getQuestionBankId().toString())
                    .collect(Collectors.toList());
            List<KnowledgeMap> knowledgeList = getKnowledgeMap(questionBankIds);
            // 8. 按知识点分组题目
            Map<String, List<QuestionInfo>> knowledgeQuestionMap = new HashMap<>();
            for (QuestionInfo question : questions) {
                knowledgeList.forEach(k->{
                    String knowledgeName = k.getKnowledge();
                    if(question.getQuestionBankId().equals(k.getQuestionUuid())) {
                        knowledgeQuestionMap.computeIfAbsent(knowledgeName, k2 -> new ArrayList<>()).add(question);
                    }
                });
            }
            // 9. 按name分组计算结果
            List<Map<String, Object>> groupedResult = new ArrayList<>();
            // 遍历每个知识点
            for (Map.Entry<String, List<QuestionInfo>> entry : knowledgeQuestionMap.entrySet()) {
                String knowledge = entry.getKey();
                List<QuestionInfo> knowledgeQuestions = entry.getValue();
                // 计算全体数据
                Map<String, Object> totalData = new HashMap<>();
                totalData.put("knowledge", knowledge);
                List<Map<String, Object>> totalScoreInfos = calculateKnowledgeScoreInfos(allSubmits, knowledgeQuestions, allScores, classInfos);
                totalData.put("knowledgeScoreInfos", totalScoreInfos);
                groupedResult.add(totalData);
            }
            return groupedResult;

        } catch (Exception e) {
            log.error("计算知识点得分率失败: {}", e.getMessage(), e);
            throw new RuntimeException("计算知识点得分率失败: " + e.getMessage());
        }
    }

    private List<Map<String, Object>> calculateKnowledgeScoreInfos(
            List<StudentSubmit> submits,
            List<QuestionInfo> knowledgeQuestions,
            List<QuestionScore> allScores, List<ClassInfo> classInfos) {
        
        if (submits.isEmpty() || knowledgeQuestions.isEmpty()) {
            return Collections.emptyList();
        }

        // 获取这些题目的ID
        Set<Long> questionIds = knowledgeQuestions.stream()
            .map(QuestionInfo::getQuestionId)
            .collect(Collectors.toSet());
            
        // 获取这些学生的提交ID
        Set<Long> submitIds = submits.stream()
            .map(StudentSubmit::getId)
            .collect(Collectors.toSet());

        // 按题目ID分组计算平均分
        Map<Long, List<QuestionScore>> questionScoreMap = allScores.stream()
            .filter(qs -> submitIds.contains(qs.getStudentSubmitId()) && 
                   questionIds.contains(qs.getQuestionId()))
            .collect(Collectors.groupingBy(QuestionScore::getQuestionId));

        // 计算每道题的得分率
        List<Map<String, Object>> scoreInfos = new ArrayList<>();
        Map<String, Object> gradeMap = new HashMap<>();
        List<String> questionNums = new ArrayList<>();
        knowledgeQuestions = knowledgeQuestions.stream().distinct().collect(Collectors.toList());

        double totalScore = 0.0;
        double totalFullScore = 0.0;
        for (QuestionInfo question : knowledgeQuestions) {
            List<QuestionScore> scores = questionScoreMap.getOrDefault(question.getQuestionId(), Collections.emptyList());
            if (!scores.isEmpty()) {
                totalScore += scores.stream().mapToDouble(QuestionScore::getScore).sum();
                totalFullScore += question.getQuestionScore() * scores.size();
            }
            Set<String> uniqueSet = new LinkedHashSet<>(questionNums);
            if(!ObjectUtils.isEmpty(question.getQuestionAlias())){
                uniqueSet.add(question.getQuestionAlias());
            }else {
                uniqueSet.add(String.valueOf(question.getQuestionNum() / 100000));
            }
            questionNums = new ArrayList<>(uniqueSet);
        }
        double scoreRate = totalFullScore > 0 ? (totalScore / totalFullScore) * 100 : 0.0;
        gradeMap.put("type", 0);
        gradeMap.put("name", "全体");
        gradeMap.put("scoreRate", String.format("%.2f", scoreRate));
        gradeMap.put("questionNumList", questionNums);
        scoreInfos.add(gradeMap);
        // 计算各班级数据
        for (ClassInfo classInfo : classInfos) {
            List<Long> classSubmitIds = submits.stream().filter(s->s.getClassId().equals(classInfo.getClassId())).map(StudentSubmit::getId).collect(Collectors.toList());
            Map<String, Object> classMap = new HashMap<>();
            String className = classInfo.getClassName();
            classMap.put("name", className);
            classMap.put("type", 1);
            double classTotalScore = 0.0;
            double classTotalFullScore = 0.0;
            List<String> classQuestionNums = new ArrayList<>();
            for (QuestionInfo question : knowledgeQuestions) {
                List<QuestionScore> scores = questionScoreMap.getOrDefault(question.getQuestionId(), Collections.emptyList())
                        .stream().filter(q-> classSubmitIds.contains(q.getStudentSubmitId())).collect(Collectors.toList());
                if (!scores.isEmpty()) {
                    classTotalScore += scores.stream().mapToDouble(QuestionScore::getScore).sum();
                    classTotalFullScore += question.getQuestionScore() * scores.size();
                }
                Set<String> uniqueSet = new LinkedHashSet<>(classQuestionNums);
                if(!ObjectUtils.isEmpty(question.getQuestionAlias())){
                    uniqueSet.add(question.getQuestionAlias());
                }else {
                    uniqueSet.add(String.valueOf(question.getQuestionNum() / 100000));
                }
                classQuestionNums = new ArrayList<>(uniqueSet);
            }
            double classScoreRate = classTotalFullScore > 0 ? (classTotalScore / classTotalFullScore) * 100 : 0.0;
            classMap.put("scoreRate",String.format("%.2f", classScoreRate));
            classMap.put("questionNumList", classQuestionNums);
            scoreInfos.add(classMap);
        }
        return scoreInfos;
    }

    /**
     * 计算分数段分布
     */
    private List<Map<String, Object>> calculateScoreRangeDistribution(List<StudentSubmit> submits, int fullScore) {
        List<Map<String, Object>> distributions = new ArrayList<>();
        if (submits == null || submits.isEmpty()) {
            return distributions;
        }

        // 定义分数段
        int[] ranges = {0, 60, 70, 80, 90, 100};

        // 计算每个分数段的人数和比例
        for (int i = 0; i < ranges.length - 1; i++) {
            int start = ranges[i];
            int end = ranges[i + 1];

            long count = submits.stream()
                    .filter(s -> s.getScore() >= start && s.getScore() < end)
                    .count();

            // 特殊处理最后一个区间，包含满分
            if (i == ranges.length - 2) {
                count = submits.stream()
                        .filter(s -> s.getScore() >= start && s.getScore() <= fullScore)
                        .count();
            }

            double percentage = (double) count / submits.size() * 100;

            Map<String, Object> distribution = new HashMap<>();
            distribution.put("range", String.format("[%d,%d)", start, end));
            if (i == ranges.length - 2) {
                distribution.put("range", String.format("[%d,%d]", start, fullScore));
            }
            distribution.put("count", count);
            distribution.put("percentage", String.format("%.1f", percentage));

            distributions.add(distribution);
        }

        return distributions;
    }

    /**
     * 计算标准差
     */
    private double calculateStandardDeviationForSubmits(List<StudentSubmit> submits) {
        if (submits == null || submits.isEmpty()) {
            return 0.0;
        }

        double mean = submits.stream()
                .mapToDouble(StudentSubmit::getScore)
                .average()
                .orElse(0.0);

        double variance = submits.stream()
                .mapToDouble(s -> Math.pow(s.getScore() - mean, 2))
                .average()
                .orElse(0.0);

        return Math.sqrt(variance);
    }

    public Map<String, Object> calculateStudentHomeworkOverview(Long examId, String studentId) {
        try {
            Map<String, Object> result = new HashMap<>();
            // 1. 获取考试详情
            ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
            ExamBase examBase = examBaseMapper.selectByExamId(examId);
            if (examDetail == null || examBase == null) {
                throw new RuntimeException("未找到考试详情");
            }
            QueryWrapper<StudentSubmit> questionScoreQueryWrapper = new QueryWrapper<>();
            questionScoreQueryWrapper.eq("student_id", studentId);
            questionScoreQueryWrapper.eq("exam_detail_id", examDetail.getId());
            StudentSubmit studentSubmit = studentSubmitMapper.selectOne(questionScoreQueryWrapper);
            if (studentSubmit == null) {
                throw new RuntimeException("未找到学生信息");
            }
            result.put("examName", examBase.getExamName());
            result.put("score", studentSubmit.getScore());
            List<PaperImage> paperImages = JSON.parseArray(studentSubmit.getPaperImages(), PaperImage.class);
            result.put("paperImage", paperImages);
            return result;
        }catch (Exception e) {
            log.error("获取学生作业情况汇总失败: {}", e.getMessage(), e);
            throw new RuntimeException("获取学生作业情况汇总失败: " + e.getMessage());
        }
    }

    /**
     * 计算班级成绩定位数据
     * @param examId 考试ID
     * @param classId 班级ID
     * @param studentId 学生ID
     * @return 包含分数、班排名、班级/全体均分及离均差的数据
     */
    public Map<String, Object> calculateClassPosition(Long examId, Long classId, String studentId) {
        Map<String, Object> result = new HashMap<>();

        ExamDetail examDetail = examDetailMapper.selectByExamId(examId);

        // 获取学生分数
        Double studentScore = scoreMapper.getStudentScore(examDetail.getId(), studentId);
        if (studentScore == null) {
            throw new RuntimeException("未找到学生成绩数据");
        }

        // 获取班级排名
        Integer classRank = scoreMapper.getStudentClassRank(examDetail.getId(), classId, studentId);

        // 获取班级均分
        Double classAvg = scoreMapper.getClassAverage(examDetail.getId(), classId);

        // 获取全体均分
        Double totalAvg = scoreMapper.getTotalAverage(examDetail.getId());

        // 计算离均差
        double classDeviation = studentScore - classAvg;
        double totalDeviation = studentScore - totalAvg;

        // 构建返回数据
        result.put("score", studentScore);
        result.put("classRank", classRank);
        result.put("classAverage", String.format("%.2f", classAvg));
        result.put("totalAverage", String.format("%.2f", totalAvg));
        result.put("deviation", String.format("%.2f/%.2f", classDeviation, totalDeviation));

        return result;
    }

    /**
     * 获取学生小题分详情
     */
    public Map<String, Object> getQuestionScores(Long examId, String studentId) {
        Map<String, Object> result = new HashMap<>();
        ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
        // 获取小题分数据
        List<Map<String, Object>> questionScores = scoreMapper.getQuestionScores(examDetail.getId(), studentId);
        // 转换题型显示
        questionScores.forEach(question -> {
            List<PaperImage> paperImages = JSON.parseArray(question.getOrDefault("paperImages","-").toString(), PaperImage.class);
            question.put("paperImages", paperImages);
            if(!ObjectUtils.isEmpty(question.get("questionAlias"))){
                question.put("questionNum", question.get("questionTypeName") + "-" + question.get("questionAlias"));
            }else {
                int bigQuestionNum = CalculateQuestionNumUtil.bigQuestionNum((Integer) question.get("questionNum"));
                int smallQuestionNum = CalculateQuestionNumUtil.smallQuestionNum((Integer) question.get("questionNum"));
                if (smallQuestionNum != 0) {
                    question.put("questionNum", bigQuestionNum + "-" + question.get("questionTypeName") + "-" + smallQuestionNum);
                } else {
                    question.put("questionNum", question.get("questionTypeName") + "-" + bigQuestionNum);
                }
            }
            // 可以添加其他题型的转换
        });

        result.put("questions", questionScores);
        return result;
    }

    /**
     * 学生错题
     */
    public List<Map<String, Object>> calculateStudentErrorQuestions(Long examId, String studentId, Integer scoreRateThreshold) {
        try {
            ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
            if (examDetail == null) {
                throw new RuntimeException("未找到考试详情");
            }
            // 获取所有题目得分情况
            List<Map<String, Object>> studentQuestionStats = questionScoreMapper.selectStudentQuestionStats(examDetail.getId(), studentId);
            // 获取所有题目ID
            List<String> questionBankIds = studentQuestionStats.stream()
                    .map(q -> q.get("questionBankId").toString())
                    .collect(Collectors.toList());

            log.info("准备获取知识点信息，题目IDs: {}", questionBankIds);

            // 调用知识点接口
            try {
                ResponseEntity<Map> response = sendPost(questionBankIds);
                if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                    Map<String, Object> responseBody = response.getBody();
                    if(ObjectUtils.isEmpty(responseBody.get("data"))){
                        return new ArrayList<>();
                    }
                    List<Map<String, Object>> questionDataList = (List<Map<String, Object>>) responseBody.get("data");

                    if (questionDataList == null || questionDataList.isEmpty()) {
                        log.warn("知识点接口返回空数据");
                        studentQuestionStats.forEach(q -> q.put("knowledge", "-"));
                    } else {
                        log.info("成功获取到{}个题目的知识点信息", questionDataList.size());

                        // 创建知识点映射
                        Map<String, String> knowledgeMap = new HashMap<>();
                        Map<String, String> degreeMap = new HashMap<>();
                        for (Map<String, Object> questionData : questionDataList) {
                            List<Map<String, Object>> knowledgeList = (List<Map<String, Object>>) questionData.get("questionKnowledgeChapterRelList");
                            String degree = questionData.containsKey("degree") && questionData.get("degree") != null
                                    ? questionData.get("degree").toString()
                                    : "";
                            String difficulty = questionData.containsKey("difficulty") && questionData.get("difficulty") != null
                                    ? questionData.get("difficulty").toString()
                                    : "";
                            if (knowledgeList != null && !knowledgeList.isEmpty()) {
                                String questionUuid = knowledgeList.get(0).get("questionUuid").toString();
                                // 将多个知识点用逗号连接
                                String knowledgePoints = knowledgeList.stream()
                                        .map(k -> k.get("knowledgeName").toString())
                                        .collect(Collectors.joining("、"));
                                knowledgeMap.put(questionUuid, knowledgePoints);
                                degreeMap.put(questionUuid, difficulty + "-" + degree);
                            }
                        }
                        // 合并知识点信息到题目统计数据
                        studentQuestionStats.forEach(q -> {
                            String questionId = q.get("questionBankId").toString();
                            q.put("knowledge", knowledgeMap.getOrDefault(questionId, "-"));
                            q.put("degree", degreeMap.getOrDefault(questionId, "-"));
                        });
                    }
                } else {
                    log.error("知识点接口返回错误状态码: {}", response.getStatusCode());
                    studentQuestionStats.forEach(q -> q.put("knowledge", "-"));
                }
            } catch (Exception e) {
                log.error("获取试题知识点失败: {}, URL: {}", e.getMessage(),
                        baseUrl + "/system/question/info/knowledge/" + questionBankIds, e);
                studentQuestionStats.forEach(q -> q.put("knowledge", "-"));
            }
            // 筛选得分率低于阈值的题目
            List<Map<String, Object>> filteredStats = studentQuestionStats.stream()
                    .filter(q -> {
                        Double scoreRate = (Double) q.get("scoreRate");
                        String difficulty = q.get("degree").toString();
                        if(!ObjectUtils.isEmpty(difficulty) && difficulty.contains("-") && difficulty.length() > 1) {
                            String[] d = difficulty.split("-");
                            q.put("difficultyDesc", d[0]);
                            q.put("difficulty", d[1]);
                        }else {
                            q.put("difficultyDesc", "");
                            q.put("difficulty", "");
                        }
                        if(!ObjectUtils.isEmpty(q.get("questionAlias"))){
                            q.put("questionNum", q.get("questionTypeName") + "-" + q.get("questionAlias"));
                        }else {
                            int bigQuestionNum = CalculateQuestionNumUtil.bigQuestionNum((Integer) q.get("questionNum"));
                            int smallQuestionNum = CalculateQuestionNumUtil.smallQuestionNum((Integer) q.get("questionNum"));
                            if (smallQuestionNum != 0) {
                                q.put("questionNum", bigQuestionNum + "-" + q.get("questionTypeName") + "-" + smallQuestionNum);
                            } else {
                                q.put("questionNum", q.get("questionTypeName") + "-" + bigQuestionNum);
                            }
                        }
                        return scoreRate < scoreRateThreshold;
                    })
                    .collect(Collectors.toList());
            filteredStats = filteredStats.stream()
                    .sorted(Comparator.comparing(
                            map -> extractStartNumber(map.get("questionNum").toString())
                    ))
                    .collect(Collectors.toList());
            log.info("找到{}个得分率低于{}%的题目", filteredStats.size(), scoreRateThreshold);
            return filteredStats;
        } catch (Exception e) {
            log.error("计算学生错题统计失败: {}", e.getMessage(), e);
            throw new RuntimeException("计算学生错题统计失败: " + e.getMessage());
        }
    }

    /**
     * 计算学生的知识点掌握情况
     * @param examId 考试ID
     * @param studentId 学生ID
     * @return 知识点得分率列表
     */
    public List<Map<String, Object>> calculateStudentKnowledge(Long examId, String studentId) {
        ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
        if (examDetail == null) {
            throw new RuntimeException("未找到考试详情");
        }
        // 获取考试所有题目信息
        List<QuestionInfo> questions = questionInfoMapper.selectByExamId(examDetail.getId());
        if (questions.isEmpty()) {
            return new ArrayList<>();
        }

        // 获取题目的知识点信息
        List<String> questionBankIds = questions.stream()
                .map(QuestionInfo::getQuestionBankId)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        //获取知识点映射
        List<KnowledgeMap> knowledgeMaps = getKnowledgeMap(questionBankIds);

        // 获取学生的答题得分情况
        List<QuestionScore> questionScores = questionScoreMapper.selectByExamAndStudent(examDetail.getId(), studentId);
        Map<Long, QuestionScore> scoreMap = questionScores.stream()
                .collect(Collectors.toMap(QuestionScore::getQuestionId, Function.identity()));
        if (questionScores == null) {
            throw new RuntimeException("未找到学生答题信息");
        }
        Map<String, KnowledgeScoreInfo> knowledgeScoreMap = new HashMap<>();
        // 按知识点分组计算得分率
        Map<String, List<KnowledgeMap>> kmap = knowledgeMaps.stream().collect(Collectors.groupingBy(KnowledgeMap::getKnowledge));
        kmap.forEach((k,v)->{
            List<String> questionUuids = v.stream().map(KnowledgeMap::getQuestionUuid).collect(Collectors.toList());
            List<Long> questionIds =  questions.stream().filter(q-> questionUuids.contains(q.getQuestionBankId())).map(QuestionInfo::getQuestionId).collect(Collectors.toList());
            List<QuestionScore> questionScoresList = questionScores.stream().filter(qs-> questionIds.contains(qs.getQuestionId())).collect(Collectors.toList());
            double questionScore = questionScoresList.stream().mapToDouble(QuestionScore::getScore).sum();
            double fullScore = questions.stream().filter(q-> questionUuids.contains(q.getQuestionBankId())).mapToDouble(QuestionInfo::getQuestionScore).sum();
            KnowledgeScoreInfo knowledgeScoreInfo = new KnowledgeScoreInfo();
            knowledgeScoreInfo.setTotalScore(questionScore);
            knowledgeScoreInfo.setTotalFullScore(fullScore);
            knowledgeScoreMap.put(k, knowledgeScoreInfo);
        });
        List<Map<String, Object>> result = new ArrayList<>();
        knowledgeScoreMap.forEach((knowledge, info) -> {
            Map<String, Object> item = new HashMap<>();
            item.put("knowledgeName", knowledge);
            item.put("scoreRate", String.format("%.2f", info.getScoreRate() * 100));
            result.add(item);
        });

        // 按得分率降序排序
        result.sort((a, b) -> {
            double rateA = Double.parseDouble(a.get("scoreRate").toString());
            double rateB = Double.parseDouble(b.get("scoreRate").toString());
            return Double.compare(rateB, rateA);
        });

        return result;
    }



    /**
     * 计算学生作业周/月汇总统计
     *
     * @param studentId   学生ID
     * @param summaryType 统计类型（week/month）
     * @return 统计数据列表
     */
    public List<Map<String, Object>> calculateStudentSummary(String studentId, String summaryType) {
        try {
            // 1. 获取时间范围
            LocalDateTime now = LocalDateTime.now();
            LocalDateTime startDate;
            if ("week".equals(summaryType)) {
                // 周度：当前日期和前6天
                startDate = now.minusDays(6);
                // 计算当前周数
            } else {
                // 月度：当前日期和前29天
                startDate = now.minusDays(29);
            }

            // 2. 获取该时间范围内的学生所有考试记录
            List<StudentSubmit> allSubmits = studentSubmitMapper.selectByStudentIdAndDateRange(studentId, startDate, now);
            if (allSubmits.isEmpty()) {
                return Collections.emptyList();
            }

            // 3. 获取学生所属班级ID (使用第一条记录的班级ID)
            Long classId = allSubmits.get(0).getClassId();

            // 4. 计算统计数据
            Map<String, Object> statistics = new HashMap<>();

            // 设置时间段
            String periodFormat = "YYYY-MM-dd";
            String formatA = startDate.format((DateTimeFormatter.ofPattern(periodFormat)));
            String formatB = now.format((DateTimeFormatter.ofPattern(periodFormat)));
            statistics.put("period", formatA + "至" + formatB);

            // 计算提交率
            long totalExamsCount = examDetailMapper.countExamsByDateRange(classId, startDate, now);
            long submittedCount = allSubmits.stream()
                    .filter(s -> s.getSubmitStatus() != null && s.getSubmitStatus() == 1)
                    .count();
            double submitRate = totalExamsCount > 0 ?
                    (double) submittedCount / totalExamsCount * 100 : 0;
            statistics.put("submittedCount", submittedCount);
            statistics.put("totalExamsCount",totalExamsCount);
            statistics.put("submitRate", String.format("%.2f%%", submitRate));

            // 计算空白率 - 所有题目的空白率
            List<Long> allExamIds = allSubmits.stream()
                    .map(StudentSubmit::getExamDetailId)
                    .collect(Collectors.toList());

            // 获取所有考试的所有题目
            long totalQuestionCount = 0;
            long blankQuestionCount = 0;

            for (Long examId : allExamIds) {
                List<QuestionInfo> questions = questionInfoMapper.selectByExamDetailId(examId);
                totalQuestionCount += questions.size();

                // 获取学生在这个考试的提交记录
                StudentSubmit submit = allSubmits.stream()
                        .filter(s -> s.getExamDetailId().equals(examId))
                        .findFirst()
                        .orElse(null);

                if (submit != null && submit.getId() != null) {
                    List<QuestionScore> questionScores = questionScoreMapper.selectByStudentSubmitId(submit.getId());

                    // 计算未作答的题目数量
                    for (QuestionInfo question : questions) {
                        boolean answered = questionScores.stream()
                                .anyMatch(qs -> qs.getQuestionId().equals(question.getQuestionId()) &&
                                        qs.getScore() != null && qs.getScore() > 0);
                        if (!answered) {
                            blankQuestionCount++;
                        }
                    }
                } else {
                    // 如果没有提交记录，所有题目都算作空白
                    blankQuestionCount += questions.size();
                }
            }

            double blankRate = totalQuestionCount > 0 ?
                    (double) blankQuestionCount / totalQuestionCount * 100 : 0;
            statistics.put("blankRate", String.format("%.2f%%", blankRate));

            // 统计各分数段的次数
            List<StudentSubmit> validSubmits = allSubmits.stream()
                    .filter(s -> s.getSubmitStatus() != null && s.getSubmitStatus() == 1 &&
                            !ObjectUtils.isEmpty(s.getScore()) && s.getScore() > 0)
                    .collect(Collectors.toList());

            // 满分次数、优秀次数、良好次数、及格次数、低分次数
            long fullScoreCount = 0;
            long excellentCount = 0;
            long goodCount = 0;
            long passCount = 0;
            long lowScoreCount = 0;

            for (StudentSubmit submit : validSubmits) {
                ExamDetail exam = examDetailMapper.selectById(submit.getExamDetailId());
                if (exam == null || exam.getFullScore() == null) continue;

                double fullScore = exam.getFullScore();
                double score = submit.getScore();

                if (score >= fullScore) {
                    fullScoreCount++;
                } else if (score >= fullScore * 0.9) {
                    excellentCount++;
                } else if (score >= fullScore * 0.8) {
                    goodCount++;
                } else if (score >= fullScore * 0.6) {
                    passCount++;
                } else {
                    lowScoreCount++;
                }
            }

            statistics.put("fullScoreCount", fullScoreCount);
            statistics.put("excellentCount", excellentCount);
            statistics.put("goodCount", goodCount);
            statistics.put("passCount", passCount);
            statistics.put("lowScoreCount", lowScoreCount);

            return Collections.singletonList(statistics);

        } catch (Exception e) {
            log.error("计算学生作业周/月汇总统计失败", e);
            throw new RuntimeException("计算学生作业周/月汇总统计失败: " + e.getMessage());
        }
    }

    /************************************校本分析*******************************************/

    /**
     * 计算年级五率对比数据（包含年级整体和各班级）
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @param subjectId 学科ID
     * @param gradeId   年级ID（可选）
     * @param classIds
     * @return 年级整体和各班级的五率统计数据
     */
    public List<Map<String, Object>> calculateGradeRatesComparison(
            LocalDate startTime,
            LocalDate endTime,
            Long subjectId,
            Long gradeId, List<Long> classIds) {
        try {
            List<GradeInfo> gradeInfoList = gradeInfoMapper.selectByGradeId(gradeId);
            if(gradeInfoList == null){
                throw new RuntimeException("未找到年级详情");
            }
            if(ObjectUtils.isEmpty(classIds)){
                List<Long> gradeInfoIds = gradeInfoList.stream().map(GradeInfo::getId).collect(Collectors.toList());
                classIds = classInfoMapper.selectClassIdsByGradeIds(gradeInfoIds).stream().distinct().collect(Collectors.toList());

            }
            // 1. 获取时间范围内的所有考试
            List<ExamDetail> examDetails = examDetailMapper.selectByDateRangeAndSubject(
                    startTime.atStartOfDay(),
                    endTime.atTime(23, 59, 59),
                    subjectId, classIds);
            if (examDetails.isEmpty()) {
                return Collections.emptyList();
            }
            // 2. 获取所有考试提交记录
            List<StudentSubmit> allSubmits = new ArrayList<>();
            Map<Long, ExamDetail> examMap = new HashMap<>();
            for (ExamDetail exam : examDetails) {
                List<StudentSubmit> submits = studentSubmitMapper.selectByExamDetailIdAndClassIds(exam.getId(), classIds);
                allSubmits.addAll(submits);
                examMap.put(exam.getId(), exam);
            }
            // 3. 按班级分组统计
            Map<Long, List<StudentSubmit>> classSubmits = allSubmits.stream().collect(Collectors.groupingBy(StudentSubmit::getClassId));
            List<Map<String, Object>> result = new ArrayList<>();
            // 4. 计算年级整体的五率
            Map<String, Object> gradeStats = calculateRates(allSubmits, examMap, "年级整体", gradeId, subjectId);
            result.add(gradeStats);

            // 5. 计算各班级的五率
            List<Map<String, Object>> classResults = new ArrayList<>();
            for (Map.Entry<Long, List<StudentSubmit>> entry : classSubmits.entrySet()) {
                Long classId = entry.getKey();
                List<StudentSubmit> submits = entry.getValue();
                ClassInfo classInfo = classInfoMapper.selectByClassId2(classId);
                if (classInfo == null) continue;
                Map<String, Object> classStats = calculateRates(submits, examMap, classInfo.getClassName(), gradeId, subjectId);
                classResults.add(classStats);
            }

            // 6. 计算各项率的排名
            String[] rateTypes = {"fullScoreRate", "excellenceRate", "goodRate", "passRate", "lowScoreRate"};
            for (String rateType : rateTypes) {
                // 按照比率从高到低排序（低分率除外）
                final boolean isAscending = rateType.equals("lowScoreRate");
                classResults.sort((a, b) -> {
                    ScoreRate rateA = (ScoreRate) a.get(rateType);
                    ScoreRate rateB = (ScoreRate) b.get(rateType);
                    double valueA = Double.parseDouble(rateA.getRate().replace("%", ""));
                    double valueB = Double.parseDouble(rateB.getRate().replace("%", ""));
                    return isAscending ? Double.compare(valueA, valueB) : Double.compare(valueB, valueA);
                });

                // 计算排名（处理同率情况）
                int currentRank = 1;
                double lastRate = -1;
                int sameRateCount = 0;

                for (int i = 0; i < classResults.size(); i++) {
                    Map<String, Object> classStats = classResults.get(i);
                    ScoreRate scoreRate = (ScoreRate) classStats.get(rateType);
                    double currentRate = Double.parseDouble(scoreRate.getRate().replace("%", ""));

                    if (i > 0 && currentRate == lastRate) {
                        sameRateCount++;
                    } else {
                        currentRank = i + 1;
                        sameRateCount = 0;
                    }
                    lastRate = currentRate;
                    // 添加排名
                    classStats.put(rateType + "Rank", currentRank);
                }
            }

            // 将班级结果添加到最终结果中
            result.addAll(classResults);
            return result;
        } catch (Exception e) {
            log.error("计算年级五率对比数据失败", e);
            throw new RuntimeException("计算年级五率对比数据失败: " + e.getMessage());
        }
    }

    /**
     * 计算五率统计数据
     *
     * @param submits   提交记录列表
     * @param examMap   考试信息映射
     * @param name      统计对象名称（年级整体/班级名称）
     * @param gradeId
     * @param subjectId
     * @return 五率统计数据
     */
    private Map<String, Object> calculateRates(List<StudentSubmit> submits, Map<Long, ExamDetail> examMap, String name, Long gradeId, Long subjectId) throws Exception {
        long totalCount = submits.size();
        if (totalCount == 0) {
            Map<String, Object> emptyStats = new HashMap<>();
            emptyStats.put("name", name);
            emptyStats.put("fullScoreRate", new ScoreRate(0L, "0.0%"));
            emptyStats.put("excellenceRate", new ScoreRate(0L, "0.0%"));
            emptyStats.put("goodRate", new ScoreRate(0L, "0.0%"));
            emptyStats.put("passRate", new ScoreRate(0L, "0.0%"));
            emptyStats.put("lowScoreRate", new ScoreRate(0L, "0.0%"));
            // 添加排名字段，空数据默认排最后
            emptyStats.put("fullScoreRateRank", Integer.MAX_VALUE);
            emptyStats.put("excellenceRateRank", Integer.MAX_VALUE);
            emptyStats.put("goodRateRank", Integer.MAX_VALUE);
            emptyStats.put("passRateRank", Integer.MAX_VALUE);
            emptyStats.put("lowScoreRateRank", Integer.MAX_VALUE);
            return emptyStats;
        }

        long fullScoreCount = 0;
        long excellentCount = 0;
        long goodCount = 0;
        long passCount = 0;
        long lowScoreCount = 0;
        AcademicLevelResult academicLevelResult = getFiveRates(subjectId, gradeId);
        for (StudentSubmit submit : submits) {
            Double score = submit.getScore();
            Integer submitStatus = submit.getSubmitStatus();
            if (score == null || submitStatus == null || submitStatus != 1) {
                continue;
            }
            ExamDetail exam = examMap.get(submit.getExamDetailId());
            if (exam == null || exam.getFullScore() == null) continue;
            double fullScore = exam.getFullScore().doubleValue();
            List<FiveRate> fiveRates = getExamFiveRates(academicLevelResult, fullScore);
            for(FiveRate fiveRate : fiveRates) {
                if (fiveRate.getType() == 0 && score == fullScore) {
                    //满分
                    fullScoreCount++;
                } else {
                    boolean b = score >= fiveRate.getStartScore() && score < fiveRate.getEndScore();
                    if (b && fiveRate.getType() == 1) {
                        //优秀
                        excellentCount++;
                    } else if (b && fiveRate.getType() == 2) {
                        //良好
                        goodCount++;
                    } else if (b && fiveRate.getType() == 3) {
                        //及格
                        passCount++;
                    } else if (b && fiveRate.getType() == 4) {
                        //低分
                        lowScoreCount++;
                    }
                }
            }
        }

        // 计算比率
        Map<String, Object> stats = new HashMap<>();
        stats.put("name", name);
        stats.put("fullScoreRate", new ScoreRate(fullScoreCount, String.format("%.1f%%", (double) fullScoreCount / totalCount * 100)));
        stats.put("excellenceRate", new ScoreRate(excellentCount, String.format("%.1f%%", (double) excellentCount / totalCount * 100)));
        stats.put("goodRate", new ScoreRate(goodCount, String.format("%.1f%%", (double) goodCount / totalCount * 100)));
        stats.put("passRate", new ScoreRate(passCount, String.format("%.1f%%", (double) passCount / totalCount * 100)));
        stats.put("lowScoreRate", new ScoreRate(lowScoreCount, String.format("%.1f%%", (double) lowScoreCount / totalCount * 100)));
        return stats;
    }

    @NotNull
    private static List<FiveRate> getExamFiveRates(AcademicLevelResult academicLevelResult, double fullScore) {
        List<FiveRate> fiveRates = new ArrayList<>();
        AcademicLevelResult.DataBean dataBean = academicLevelResult.getData().stream().filter(d-> d.getType() == 1).collect(Collectors.toList()).get(0);
        for(AcademicLevelResult.DataBean.AcademiclevelsBean academiclevelsBean: dataBean.getAcademiclevels()){
            FiveRate fiveRate = new FiveRate();
            if(academiclevelsBean.getName().equals(ScoreFiveRateConstants.FullScoreRate)) {
                fiveRate.setType(0);
            }else if(academiclevelsBean.getName().equals(ScoreFiveRateConstants.ExcellentScoreRate)) {
                fiveRate.setType(1);
            }else if (academiclevelsBean.getName().equals(ScoreFiveRateConstants.GoodScoreRate)) {
                fiveRate.setType(2);
            }else if (academiclevelsBean.getName().equals(ScoreFiveRateConstants.PassScoreRate)) {
                fiveRate.setType(3);
            }else {
                fiveRate.setType(4);
            }
            Double startScore = fullScore * (academiclevelsBean.getStartScore()/100.0);
            Double endScore = fullScore * (academiclevelsBean.getEndScore()/100.0);
            //计算分数
            fiveRate.setStartScore(startScore);
            fiveRate.setEndScore(endScore);
            fiveRates.add(fiveRate);
        }
        return fiveRates;
    }

    /**
     * 小程序获取错题uuid列表
     * @param examId
     * @param studentId
     * @return
     */
    public List<String> calculateStudentErrorQuestionIds(Long examId, String studentId) {
        try {
            List<String> result = new ArrayList<>();
            ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
            if(ObjectUtils.isEmpty(examDetail)){
                throw new RuntimeException("未找到作业信息");
            }
            StudentSubmit studentSubmit = studentSubmitMapper.selectByExamAndStudent(examDetail.getId(), studentId);
            List<QuestionScore> questionScores = questionScoreMapper.selectBySubmitId(studentSubmit.getId());
            List<QuestionInfo> questionInfos = questionInfoMapper.selectByExamId(examDetail.getId());
            for(QuestionScore questionScore : questionScores) {
                QuestionInfo questionInfo = questionInfos.stream().filter(qi-> qi.getQuestionId().equals(questionScore.getQuestionId())).collect(Collectors.toList()).get(0);
                if(!Objects.equals(questionScore.getScore(), questionInfo.getQuestionScore())){
                    result.add(questionInfo.getQuestionBankId());
                }
            }
            return result;
        } catch (Exception e) {
            log.error("获取学生错题列表数据失败", e);
            throw new RuntimeException("获取学生错题列表数据失败: " + e.getMessage());
        }
    }

    public String excel(List<Map<String, Object>> data, ExamBase examBase, ExamDetail examDetail, ClassInfo classInfo, Integer type) {
        // 构建完整路径
        String datePath = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
        File excelFile = new File(excelPath + "/upload/" + datePath);
        try {
            // 确保目录存在
            if (!excelFile.exists()) {
                if (excelFile.mkdirs()) {
                    System.out.println("成功创建目录: " + excelFile);
                } else {
                    throw new IOException("无法创建目录: " + excelFile);
                }
            }

            String httpUrl = "";
            if(!ObjectUtils.isEmpty(classInfo)){
                httpUrl += examDetail.getSubjectName() + "-" + examBase.getExamName() + "-"+ classInfo.getClassName() + "-成绩单.xlsx";
            }else {
                httpUrl += examDetail.getSubjectName() + "-" + examBase.getExamName() + "-成绩单.xlsx";
            }
            // 添加文件名
            File fullPath = new File(excelFile, httpUrl);
            // 调用生成方法
            ExcelGenerator.generateExcel(data, fullPath.getAbsolutePath(), type);
            return  "/upload/" + datePath + "/" + httpUrl;
        } catch (IOException e) {
            e.printStackTrace();
            System.err.println("生成Excel失败: " + e.getMessage());
            // 可以在这里添加更友好的异常处理或抛出自定义异常
        }
        return null;
    }

    class ScoreRate {
        private Long people;
        private String rate;

        public ScoreRate(Long people, String rate) {
            this.people = people;
            this.rate = rate;
        }

        public Long getPeople() {
            return people;
        }

        public String getRate() {
            return rate;
        }
    }

    @NotNull
    private AcademicLevelResult getFiveRates(Long subjectId, Long gradeId) throws Exception {
        String url = yjUrl + "/api/academiclevel/parameter";
        String response = HttpUtils.sendGet(url, "subjectId=" + subjectId + "&gradeId=" + gradeId);
        try {
            AcademicLevelResult academicLevelResult = JSON.parseObject(response, AcademicLevelResult.class);
            return academicLevelResult;
        }catch (Exception e) {
            throw new Exception(e.getMessage());
        }
    }
    /**
     * 计算作业提交情况对比数据
     *
     * @param startTime 开始日期
     * @param endTime   结束日期
     * @param subjectId 学科ID
     * @param gradeId   年级ID
     * @param classIds
     * @return 年级及各班级每天的作业提交率
     */
    public List<ExamSubmitRateVo> calculateHomeworkSubmitComparison(
            LocalDate startTime,
            LocalDate endTime,
            Long subjectId,
            Long gradeId, List<Long> classIds) {
        try {
            List<GradeInfo> gradeInfoList = gradeInfoMapper.selectByGradeId(gradeId);
            if(ObjectUtils.isEmpty(gradeInfoList)){
                throw new RuntimeException("未找到年级详情");
            }
            if(ObjectUtils.isEmpty(classIds)){
                List<Long> gradeInfoIds = gradeInfoList.stream().map(GradeInfo::getId).collect(Collectors.toList());
                classIds = classInfoMapper.selectClassIdsByGradeIds(gradeInfoIds).stream().distinct().collect(Collectors.toList());

            }
            List<ClassInfo> classes = classInfoMapper.selectByClassIds(classIds);
            if(classes == null){
                throw new RuntimeException("未找到班级详情");
            }
            // 1. 获取时间范围内的所有考试
            List<ExamDetail> examDetails = examDetailMapper.selectByDateRangeAndSubject(
                    startTime.atStartOfDay(),
                    endTime.atTime(23, 59, 59),
                    subjectId, classIds);
            if (examDetails.isEmpty()) {
                return Collections.emptyList();
            }
            List<Long> examIds = examDetails.stream().map(ExamDetail::getExamId).collect(Collectors.toList());
            List<ExamBase> examBaseList = examBaseMapper.selectByExamIds(examIds);
            //获取每个examDetail的试题数量
            List<Long> examDetailIds = examDetails.stream().map(ExamDetail::getId).collect(Collectors.toList());
            List<Map<String, Object>> examQuestionNumbers = questionInfoMapper.selectByExamDetailIds(examDetailIds);
            // 4. 获取年级整体的提交情况
            List<ExamSubmitRateVo> submitRateVos = new ArrayList<>();
            List<SubmitStatistics> submitStatistics = submitStatisticsMapper.selectListByClassIds(classIds);
            submitStatistics = submitStatistics.stream().filter(ss-> examDetailIds.contains(ss.getExamDetailId())).collect(Collectors.toList());
            //计算年级的
            getGradeSubmitRate(submitStatistics, submitRateVos, examDetails, examBaseList, examQuestionNumbers);
            Map<Long, List<SubmitStatistics>> classMaps = submitStatistics.stream().collect(Collectors.groupingBy(SubmitStatistics::getClassId));
            //获取班级的所有提交率数据
            classMaps.forEach((k, v)->{
                ExamSubmitRateVo examSubmitRateVo = new ExamSubmitRateVo();
                ClassInfo classInfo = classes.stream().filter(c-> c.getClassId().equals(k)).findFirst().orElse(null);
                if(classInfo == null){
                    throw new RuntimeException("未匹配到班级作业");
                }
                examSubmitRateVo.setName(classInfo.getClassName());
                examSubmitRateVo.setType(1);
                //先按照examId 进行分组
                List<SubmitStatisticsDTO> submitStatisticsDTOList = getExamSubmitRate(v, examDetails, examBaseList, examQuestionNumbers);
                examSubmitRateVo.setSubmitStatisticsDTOList(submitStatisticsDTOList);
                submitRateVos.add(examSubmitRateVo);
            });
            return submitRateVos;
        } catch (Exception e) {
            log.error("计算作业提交情况对比数据失败", e);
            throw new RuntimeException("计算作业提交情况对比数据失败: " + e.getMessage());
        }
    }
    private void getGradeSubmitRate(List<SubmitStatistics> submitStatistics, List<ExamSubmitRateVo> submitRateVos, List<ExamDetail> examDetails, List<ExamBase> examBaseList, List<Map<String, Object>> examQuestionNumbers) {
        ExamSubmitRateVo examSubmitRateVo = new ExamSubmitRateVo();
        examSubmitRateVo.setType(0);
        examSubmitRateVo.setName("全体");
        List<SubmitStatisticsDTO> submitStatisticsDTOList = getExamSubmitRate(submitStatistics, examDetails, examBaseList, examQuestionNumbers);
        examSubmitRateVo.setSubmitStatisticsDTOList(submitStatisticsDTOList);
        submitRateVos.add(examSubmitRateVo);
    }

    private static List<SubmitStatisticsDTO> getExamSubmitRate(List<SubmitStatistics> v, List<ExamDetail> examDetails, List<ExamBase> examBaseList, List<Map<String, Object>> examQuestionNumbers) {
        Map<Long, List<SubmitStatistics>> examMaps = v.stream().collect(Collectors.groupingBy(SubmitStatistics::getExamDetailId));
        List<SubmitStatisticsDTO> submitStatisticsDTOList = new ArrayList<>();
        examMaps.forEach((k2, v2)->{
            Object questionNumber = examQuestionNumbers.stream().filter(eqn-> eqn.get("examDetailId").equals(k2)).collect(Collectors.toList()).get(0).get("questionNumber");
            SubmitStatisticsDTO submitStatisticsDTO = new SubmitStatisticsDTO();
            ExamDetail examDetail = examDetails.stream().filter(e-> e.getId().equals(k2)).findFirst().orElse(null);
            if(examDetail == null){
                throw new RuntimeException("未匹配到作业");
            }
            ExamBase examBase = examBaseList.stream().filter(e-> e.getExamId().equals(examDetail.getExamId())).findFirst().orElse(null);
            if(examBase == null){
                throw new RuntimeException("未匹配到作业");
            }
            int totalSubmitCount = v2.stream().mapToInt(SubmitStatistics::getSubmitStudents).sum();
            int totalStudentCount = v2.stream().mapToInt(SubmitStatistics::getTotalStudents).sum();
            Double submitRate = BigDecimal.valueOf(totalSubmitCount * 100 / totalStudentCount).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
            submitStatisticsDTO.setQuestionNumber(questionNumber.toString());
            submitStatisticsDTO.setSubmitRate(submitRate);
            submitStatisticsDTO.setExamName(examBase.getExamName());
            submitStatisticsDTO.setExamTime(examBase.getStartTime());
            submitStatisticsDTOList.add(submitStatisticsDTO);
        });
        return submitStatisticsDTOList;
    }

    public List<KnowledgeScoreRateVo>  calculateGradeKnowledgeScoreRates(LocalDate startTime, LocalDate endTime, Long subjectId, Long gradeId, List<Long> classIds) {
        try {
            List<GradeInfo> gradeInfoList = gradeInfoMapper.selectByGradeId(gradeId);
            if(ObjectUtils.isEmpty(gradeInfoList)){
                throw new RuntimeException("未找到年级详情");
            }
            if(ObjectUtils.isEmpty(classIds)){
                List<Long> gradeInfoIds = gradeInfoList.stream().map(GradeInfo::getId).collect(Collectors.toList());
                classIds = classInfoMapper.selectClassIdsByGradeIds(gradeInfoIds).stream().distinct().collect(Collectors.toList());
            }
            List<KnowledgeScoreRateVo> knowledgeScoreRateVos = new ArrayList<>();
            // 1. 获取时间范围内的所有考试
            List<ExamDetail> examDetails = examDetailMapper.selectByDateRangeAndSubject(
                    startTime.atStartOfDay(),
                    endTime.atTime(23, 59, 59),
                    subjectId, classIds);
            if(examDetails.isEmpty()){
                return knowledgeScoreRateVos;
            }
            List<Long> examDetailIds = examDetails.stream().map(ExamDetail::getId).collect(Collectors.toList());
            
            // 获取所有班级信息
            List<ClassInfo> allClassInfos = classInfoMapper.selectByClassIdsAndExamIds(classIds, examDetailIds);

            // 按班级分组获取学生提交记录
            Map<Long, List<StudentSubmit>> classSubmitsMap = new HashMap<>();
            for (Long classId : classIds) {
                List<StudentSubmit> classSubmits = studentSubmitMapper.selectByExamDetailIdsAndClassIds(examDetailIds, Collections.singletonList(classId));
                classSubmitsMap.put(classId, classSubmits);
            }

            // 获取所有学生提交记录（用于计算年级整体）
            List<StudentSubmit> allSubmits = studentSubmitMapper.selectByExamDetailIdsAndClassIds(examDetailIds, classIds);
            if(allSubmits.isEmpty()){
                throw new RuntimeException("未找到提交记录，无法生成成绩分析数据");
            }
            // 获取所有题目信息
            List<Long> allStudentSubmitIds = allSubmits.stream().map(StudentSubmit::getId).distinct().collect(Collectors.toList());
            List<QuestionScore> allQuestionScores = questionScoreMapper.selectByStudentSubmitIds(allStudentSubmitIds);
            List<Long> questionIds = allQuestionScores.stream().map(QuestionScore::getQuestionId).distinct().collect(Collectors.toList());
            List<QuestionInfo> questionInfos = questionInfoMapper.selectListByQuestionIds(questionIds);

            // 获取知识点映射
            List<String> questionBankIds = questionInfos.stream()
                    .map(QuestionInfo::getQuestionBankId)
                    .distinct()
                    .collect(Collectors.toList());
            List<KnowledgeMap> knowledgeList = getKnowledgeMap(questionBankIds);

            // 创建结果列表
            // 计算年级整体的知识点得分率
            List<Map<String, Object>> gradeResult = calculateKnowledgeScoreRatesForSubmits( questionInfos, knowledgeList, "年级", allQuestionScores);
            List<Map<String, Object>> result = new ArrayList<>(gradeResult);

            // 计算各班级的知识点得分率
            for (Long classId : classIds) {
                List<StudentSubmit> classSubmits = classSubmitsMap.get(classId);
                List<Long> classSubmitIds = classSubmits.stream().map(StudentSubmit::getId).collect(Collectors.toList());
                List<QuestionScore> classQuestionScores = allQuestionScores.stream().filter(qs-> classSubmitIds.contains(qs.getStudentSubmitId())).collect(Collectors.toList());
                ClassInfo classInfo = allClassInfos.stream().filter(c-> c.getClassId().equals(classId)).findFirst().orElse(null);
                if(classInfo ==null){
                    continue;
                }
                String className = classInfo.getClassName();
                if (!classSubmits.isEmpty()) {
                    List<Map<String, Object>> classResult = calculateKnowledgeScoreRatesForSubmits(questionInfos, knowledgeList, className, classQuestionScores);
                    result.addAll(classResult);
                }
            }
            Map<Object, List<Map<String, Object>>> result2 = groupByKnowledge(result);

            result2.forEach((k, v)->{
                KnowledgeScoreRateVo knowledgeScoreRateVo = new KnowledgeScoreRateVo();
                knowledgeScoreRateVo.setKnowledgeName(k.toString());
                List<KnowLedgeScoreRate> knowLedgeScoreRateList = new ArrayList<>();
                for(Map<String, Object> map : v){
                    KnowLedgeScoreRate knowLedgeScoreRate = new KnowLedgeScoreRate();
                    //knowLedgeScoreRate.setKnowledge(map.getOrDefault("knowledge", "-").toString());
                    knowLedgeScoreRate.setGroupName(map.getOrDefault("groupName", "").toString());
                    knowLedgeScoreRate.setKnowledgeScoreRate(map.getOrDefault("knowledgeScoreRate", "").toString());
                    knowLedgeScoreRateList.add(knowLedgeScoreRate);
                }
                knowledgeScoreRateVo.setKnowLedgeScoreRateList(knowLedgeScoreRateList);
                knowledgeScoreRateVos.add(knowledgeScoreRateVo);
            });
            return knowledgeScoreRateVos;
        } catch (Exception e) {
            log.error("计算知识点得分率失败: {}", e.getMessage(), e);
            throw new RuntimeException("计算知识点得分率失败: " + e.getMessage());
        }
    }

    public static Map<Object, List<Map<String, Object>>> groupByKnowledge(List<Map<String, Object>> result) {
        Map<Object, List<Map<String, Object>>> groupedResult = new HashMap<>();
        for (Map<String, Object> map : result) {
            Object knowledge = map.get("knowledge");
            if (knowledge != null) {
                groupedResult.computeIfAbsent(knowledge, k -> new ArrayList<>()).add(map);
            }
        }
        return groupedResult;
    }
    private List<Map<String, Object>> calculateKnowledgeScoreRatesForSubmits(
            List<QuestionInfo> allQuestionInfos,
            List<KnowledgeMap> knowledgeMap,
            String groupName, List<QuestionScore> allQuestionScores) {
        // 计算每个知识点的得分率
        List<Map<String, Object>> knowledgeRates = new ArrayList<>();
        List<KnowledgeQuestion> knowledgeQuestionList = new ArrayList<>();
        knowledgeMap.forEach(map -> {
            KnowledgeQuestion knowledgeQuestion = new KnowledgeQuestion();
            knowledgeQuestion.setKnowledgeName(map.getKnowledge());
            knowledgeQuestion.setQuestionBankId(map.getQuestionUuid());
            knowledgeQuestionList.add(knowledgeQuestion);
        });
        Map<String, List<KnowledgeQuestion>> map = knowledgeQuestionList.stream().collect(Collectors.groupingBy(KnowledgeQuestion::getKnowledgeName));
        map.forEach((k, v)->{
            String knowledge = k;
            List<String> questionBankIds = v.stream().map(KnowledgeQuestion::getQuestionBankId).collect(Collectors.toList());
            List<QuestionInfo> questionInfos = allQuestionInfos.stream().filter(q-> questionBankIds.contains(q.getQuestionBankId())).collect(Collectors.toList());
            List<Long> questionIds = questionInfos.stream().map(QuestionInfo::getQuestionId).collect(Collectors.toList());
            List<QuestionScore> scoreInfo = allQuestionScores.stream().filter(qs-> questionIds.contains(qs.getQuestionId())).collect(Collectors.toList());
            List<Long> submitIds = scoreInfo.stream().map(QuestionScore::getStudentSubmitId).distinct().collect(Collectors.toList());
            double totalQuestionScore = questionInfos.stream().mapToDouble(QuestionInfo::getQuestionScore).sum() * submitIds.size();
            double totalStudentScore = scoreInfo.stream().mapToDouble(QuestionScore::getScore).sum();
            double scoreRate = 0;
            if(totalQuestionScore > 0){
                scoreRate = totalStudentScore / totalQuestionScore * 100;
            }
            // 计算得分率
            Map<String, Object> knowledgeRate = new HashMap<>();
            knowledgeRate.put("groupName", groupName);
            knowledgeRate.put("knowledge", knowledge);
            knowledgeRate.put("knowledgeScoreRate", String.format("%.0f%%", scoreRate));
            knowledgeRates.add(knowledgeRate);
        });
        return knowledgeRates;
    }

    /**年级高频错题**/
    public List<Map<String, Object>> calculateGradeErrorQuestions(Long subjectId, Long gradeId, Integer scoreRateThreshold, LocalDate startTime, LocalDate endTime, List<Long> classIds, Integer type) {
        try {
            List<GradeInfo> gradeInfoList = gradeInfoMapper.selectByGradeId(gradeId);
            if (ObjectUtils.isEmpty(gradeInfoList)) {
                throw new RuntimeException("未找到年级详情");
            }
            if(ObjectUtils.isEmpty(classIds)){
                List<Long> gradeInfoIds = gradeInfoList.stream().map(GradeInfo::getId).collect(Collectors.toList());
                classIds = classInfoMapper.selectClassIdsByGradeIds(gradeInfoIds).stream().distinct().collect(Collectors.toList());
            }
            // 1. 获取时间范围内的所有考试
            List<ExamDetail> examDetails = examDetailMapper.selectByDateRangeAndSubject(
                    startTime.atStartOfDay(),
                    endTime.atTime(23, 59, 59),
                    subjectId, classIds);
            if (examDetails.isEmpty()) {
                return Collections.emptyList();
            }
            List<Long> examIds = examDetails.stream().map(ExamDetail::getExamId).collect(Collectors.toList());
            List<ExamBase> examBaseList = examBaseMapper.selectByExamIds(examIds);
            //获取所有学生的得分情况
            List<Long> examDetailIds = examDetails.stream().map(ExamDetail::getId).collect(Collectors.toList());
            //获取班级提交的记录
            List<StudentSubmit> studentSubmitList = studentSubmitMapper.selectByExamDetailIdsAndClassIds(examDetailIds, classIds);
            //获取题目得分情况
            List<Long> studentSubmitIds = studentSubmitList.stream().map(StudentSubmit::getId).distinct().collect(Collectors.toList());
            List<QuestionScore> questionStats = questionScoreMapper.selectByStudentSubmitIds(studentSubmitIds);
            //获取试题信息
            List<Long> questionIds = questionStats.stream().map(QuestionScore::getQuestionId).distinct().collect(Collectors.toList());
            List<QuestionInfo> questionInfos = questionInfoMapper.selectListByQuestionIds(questionIds);

            // 获取所有题目ID
            List<String> questionBankIds = questionInfos.stream()
                    .map(q -> q.getQuestionBankId().toString())
                    .collect(Collectors.toList());

            // 获取知识点信息
            Map<String, String> knowledgeMap = new HashMap<>();
            try {
                ResponseEntity<Map> response = sendPost(questionBankIds);
                if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                    Map<String, Object> responseBody = response.getBody();
                    if(ObjectUtils.isEmpty(responseBody.get("data"))){
                        return new ArrayList<>();
                    }
                    List<Map<String, Object>> questionDataList = (List<Map<String, Object>>) responseBody.get("data");
                    if (questionDataList != null && !questionDataList.isEmpty()) {
                        for (Map<String, Object> questionData : questionDataList) {
                            List<Map<String, Object>> knowledgeList = (List<Map<String, Object>>) questionData.get("questionKnowledgeChapterRelList");
                            if (knowledgeList != null && !knowledgeList.isEmpty()) {
                                String questionUuid = knowledgeList.get(0).get("questionUuid").toString();
                                String knowledgePoints = knowledgeList.stream()
                                        .map(k -> k.get("knowledgeName").toString())
                                        .collect(Collectors.joining("、"));
                                knowledgeMap.put(questionUuid, knowledgePoints);
                            }
                        }
                    }
                }
            } catch (Exception e) {
                log.error("获取试题知识点失败: {}", e.getMessage(), e);
            }

            // 获取所有班级信息
            List<ClassInfo> allClassInfos = classInfoMapper.selectByClassIdsAndExamIds(classIds,examDetailIds);
            // 按班级和题目分组计算得分率
            Map<Long, Map<Long, List<QuestionScore>>> classQuestionScores = questionStats.stream()
                    .collect(Collectors.groupingBy(
                            qs -> studentSubmitList.stream()
                                    .filter(ss -> ss.getId().equals(qs.getStudentSubmitId()))
                                    .findFirst()
                                    .map(StudentSubmit::getClassId)
                                    .orElse(0L),
                            Collectors.groupingBy(QuestionScore::getQuestionId)
                    ));

            // 构建最终返回结果
            List<Map<String, Object>> result = new ArrayList<>();
            for (QuestionInfo questionInfo : questionInfos) {
                Map<String, Object> questionData = new HashMap<>();
                Long examId = examDetails.stream().filter(eb-> eb.getId().equals(questionInfo.getExamDetailId())).findFirst().get().getExamId();
                String examName = examBaseList.stream().filter(eb-> eb.getExamId().equals(examId)).findFirst().get().getExamName();
                questionData.put("examName", examName);
                questionData.put("questionId", questionInfo.getQuestionId());
                if(!ObjectUtils.isEmpty(questionInfo.getQuestionAlias())){
                    questionData.put("questionNum", questionInfo.getQuestionTypeName() + "-" + questionInfo.getQuestionAlias());
                }else {
                    int bigQuestionNum = CalculateQuestionNumUtil.bigQuestionNum(questionInfo.getQuestionNum());
                    int smallQuestionNum = CalculateQuestionNumUtil.smallQuestionNum(questionInfo.getQuestionNum());
                    if (smallQuestionNum != 0) {
                        questionData.put("questionNum", bigQuestionNum + "-" + questionInfo.getQuestionTypeName() + "-" + smallQuestionNum);
                    } else {
                        questionData.put("questionNum", questionInfo.getQuestionTypeName() + "-" + bigQuestionNum);
                    }
                }
                questionData.put("questionTypeName", questionInfo.getQuestionTypeName()); // 使用实际的题型
                questionData.put("knowledgeList", knowledgeMap.getOrDefault(questionInfo.getQuestionBankId().toString(), "-"));
                // 计算各班级得分率
                List<Map<String, String>> classScoreRateMaps = new ArrayList<>();
                List<Long> examClassIds = allClassInfos.stream().filter(c-> c.getExamDetailId().equals(questionInfo.getExamDetailId())).map(ClassInfo::getClassId).collect(Collectors.toList());
                for (Long classId : examClassIds) {
                    boolean hasLowScoreRate = false;
                    Map<String, String> scoreRateMap = new HashMap<>();
                    ClassInfo classInfo = allClassInfos.stream().filter(c-> c.getClassId().equals(classId)).findFirst().get();
                    String className = classInfo.getClassName();
                    if (className == null) continue;
                    List<QuestionScore> scores = classQuestionScores
                            .getOrDefault(classId, Collections.emptyMap())
                            .getOrDefault(questionInfo.getQuestionId(), Collections.emptyList());
                    scoreRateMap.put("className", className);
                    if (!scores.isEmpty()) {
                        double avgScoreRate = scores.stream()
                                .mapToDouble(qs -> {
                                    if (questionInfo.getQuestionScore() <= 0) return 0.0;
                                    return (qs.getScore() / questionInfo.getQuestionScore()) * 100;
                                })
                                .average()
                                .orElse(0.0);

                        scoreRateMap.put("scoreRate", String.format("%.2f%%", avgScoreRate));
                        if(type == 1 && avgScoreRate <= scoreRateThreshold){
                            hasLowScoreRate = true;
                        }else if(type != 1 && avgScoreRate >= scoreRateThreshold){
                            hasLowScoreRate = true;
                        }
                    } else {
                        scoreRateMap.put("scoreRate", "-");
                    }
                    if(hasLowScoreRate) {
                        classScoreRateMaps.add(scoreRateMap);
                    }
                }
                questionData.put("classScoreRateMaps", classScoreRateMaps);
                // 只添加得分率低于阈值的题目
                result.add(questionData);
            }
            result = result.stream().filter(r-> !ObjectUtils.isEmpty(r.get("classScoreRateMaps"))).collect(Collectors.toList());
            return result;
        } catch (Exception e) {
            log.error("计算高频错题统计失败: {}", e.getMessage(), e);
            throw new RuntimeException("计算高频错题统计失败: " + e.getMessage());
        }
    }

    public List<Map<String, Object>> calculateGradeKnowledgeScoreRatesChart(LocalDate startTime, LocalDate endTime, Long subjectId, Long gradeId, List<Long> classIds) {
        try {
            List<GradeInfo> gradeInfoList = gradeInfoMapper.selectByGradeId(gradeId);
            if (gradeInfoList == null) {
                throw new RuntimeException("未找到年级详情");
            }
            if (ObjectUtils.isEmpty(classIds)) {
                List<Long> gradeInfoIds = gradeInfoList.stream().map(GradeInfo::getId).collect(Collectors.toList());
                classIds = classInfoMapper.selectClassIdsByGradeIds(gradeInfoIds).stream().distinct().collect(Collectors.toList());
            }

            // 1. 获取时间范围内的所有考试
            List<ExamDetail> examDetails = examDetailMapper.selectByDateRangeAndSubject(
                    startTime.atStartOfDay(),
                    endTime.atTime(23, 59, 59),
                    subjectId, classIds);
            if (examDetails.isEmpty()) {
                return Collections.emptyList();
            }

            // 2. 获取考试名称映射
            List<Long> examIds = examDetails.stream().map(ExamDetail::getExamId).collect(Collectors.toList());
            List<ExamBase> examBases = examBaseMapper.selectByExamIds(examIds);
            Map<Long, String> examNameMap = examBases.stream()
                    .collect(Collectors.toMap(ExamBase::getExamId, ExamBase::getExamName));

            // 3. 获取班级名称映射
            List<Long> examDetailIds = examDetails.stream().map(ExamDetail::getId).collect(Collectors.toList());
            List<ClassInfo> classInfos = classInfoMapper.selectByClassIdsAndExamIds(classIds, examDetailIds);
            // 4. 获取所有学生提交记录
            List<StudentSubmit> allSubmits = studentSubmitMapper.selectByExamDetailIdsAndClassIds(examDetailIds, classIds);

            // 5. 获取所有题目得分记录
            List<Long> submitIds = allSubmits.stream().map(StudentSubmit::getId).distinct().collect(Collectors.toList());
            List<QuestionScore> allScores = questionScoreMapper.selectByStudentSubmitIds(submitIds);

            // 6. 获取题目信息
            List<Long> questionIds = allScores.stream().map(QuestionScore::getQuestionId).distinct().collect(Collectors.toList());
            List<QuestionInfo> questions = questionInfoMapper.selectListByQuestionIds(questionIds);

            // 7. 获取知识点映射
            List<String> questionBankIds = questions.stream()
                    .map(QuestionInfo::getQuestionBankId)
                    .map(Object::toString)
                    .collect(Collectors.toList());
            List<KnowledgeMap> knowledgeList = getKnowledgeMap(questionBankIds);

            // 8. 按知识点分组题目
            Map<String, List<QuestionInfo>> knowledgeQuestionMap = new HashMap<>();
            for (QuestionInfo question : questions) {
                knowledgeList.forEach(k->{
                    String knowledgeName = k.getKnowledge();
                    if(question.getQuestionBankId().equals(k.getQuestionUuid())) {
                        knowledgeQuestionMap.computeIfAbsent(knowledgeName, k2 -> new ArrayList<>()).add(question);
                    }
                });
            }

            // 9. 生成结果
            List<Map<String, Object>> result = new ArrayList<>();
            knowledgeQuestionMap.forEach((k, v)->{
                String knowledgeName = k;
                List<QuestionInfo> knowledgeQuestions = v;
                Map<String, Object> allknowledgeData = new HashMap<>();
                allknowledgeData.put("knowledgeName", knowledgeName);
                List<String> bankIds = knowledgeQuestions.stream().map(QuestionInfo::getQuestionBankId).collect(Collectors.toList());
                allknowledgeData.put("questionBankIds", bankIds);
                // 按考试和班级计算得分率
                List<Map<String, Object>> knowledgeDatas = new ArrayList<>();
                for (ExamDetail examDetail : examDetails) {
                    Map<String, Object> knowledgeData = new HashMap<>();
                    String examName = examNameMap.get(examDetail.getExamId());
                    knowledgeData.put("examName", examName);
                    List<Long> examClassIds = classInfos.stream().filter(c-> c.getExamDetailId().equals(examDetail.getId())).collect(Collectors.toList()).stream().map(ClassInfo::getClassId).collect(Collectors.toList());
                    List<Map<String, Object>> examClassScores = new ArrayList<>();
                    for (Long classId : examClassIds) {
                        ClassInfo classInfo = classInfos.stream().filter(ci-> ci.getExamDetailId().equals(examDetail.getId()) && classId.equals(ci.getClassId())).findFirst().orElse(null);
                        String className = classInfo.getClassName();
                        if(className == null){
                            continue;
                        }
                        // 获取该班级在该考试的提交记录
                        List<StudentSubmit> classExamSubmits = allSubmits.stream()
                                .filter(s -> s.getExamDetailId().equals(examDetail.getId())
                                        && s.getClassId().equals(classId))
                                .collect(Collectors.toList());

                        // 计算得分率
                        double scoreRate = calculateKnowledgeScoreRate(
                                classExamSubmits,
                                knowledgeQuestions,
                                allScores
                        );
                        Map<String, Object> scoreData = new HashMap<>();
                        scoreData.put("className", className);
                        scoreData.put("classId", classId);
                        scoreData.put("scoreRate", String.format("%.2f%%", scoreRate));
                        examClassScores.add(scoreData);
                        examClassScores = examClassScores.stream().distinct().collect(Collectors.toList());
                        knowledgeData.put("classKnowledgeList", examClassScores);
                    }
                    knowledgeDatas.add(knowledgeData);
                    allknowledgeData.put("knowledgeDataList", knowledgeDatas);
                }
                result.add(allknowledgeData);
            });
            return result;
        } catch (Exception e) {
            log.error("计算知识点得分率失败: {}", e.getMessage(), e);
            throw new RuntimeException("计算知识点得分率失败: " + e.getMessage());
        }
    }

    // 新增辅助方法：计算知识点得分率
    private double calculateKnowledgeScoreRate(
            List<StudentSubmit> submits,
            List<QuestionInfo> knowledgeQuestions,
            List<QuestionScore> allQuestionScores) {
        
        // 获取这些题目的ID
        Set<Long> questionIds = knowledgeQuestions.stream()
            .map(QuestionInfo::getQuestionId)
            .collect(Collectors.toSet());
            
        // 计算总分和满分
        double totalScore = 0.0;
        double totalFullScore = 0.0;
        
        for (StudentSubmit submit : submits) {
            List<QuestionScore> stuQuestionScores = allQuestionScores.stream()
                    .filter(qs -> qs.getStudentSubmitId().equals(submit.getId())).collect(Collectors.toList());
            // 获取该学生在这些题目上的得分
            List<QuestionScore> questionScores = stuQuestionScores.stream()
                .filter(qs -> questionIds.contains(qs.getQuestionId()))
                .collect(Collectors.toList());
                
            for (QuestionScore score : questionScores) {
                QuestionInfo questionInfo = knowledgeQuestions.stream().filter(q -> q.getQuestionId().equals(score.getQuestionId())).findFirst().orElse(null);
                totalScore += score.getScore();
                totalFullScore += questionInfo.getQuestionScore();
            }
        }
        
        // 计算得分率
        return totalFullScore > 0 ? (totalScore / totalFullScore) * 100 : 0;
    }

    @NotNull
    private ResponseEntity<Map> sendPost(List<String> questionBankIds) {
        String url = baseUrl + "/system/question/info/get/knowledge";
        log.info("调用知识点接口URL: {}", url);

        // 创建请求体
        Map<String, Object> requestBody = new HashMap<>();
        requestBody.put("questionUUids", questionBankIds);

        // 创建RestTemplate实例
        RestTemplate restTemplate = new RestTemplate();
        // 设置请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        // 创建HttpEntity，包含请求体和请求头
        HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
        // 发送POST请求
        ResponseEntity<Map> response = restTemplate.exchange(
                url,
                HttpMethod.POST,
                requestEntity,
                Map.class
        );
        log.info("知识点接口响应状态: {}", response.getStatusCode());
        return response;
    }


    public List<Map<String, Object>> calculateGradeHomeworkQuality(Long examId, List<Long> classIds) {
        try {
            ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
            if (examDetail == null) {
                throw new RuntimeException("未找到考试详情");
            }

            // 获取学生提交记录
            List<StudentSubmit> submits = studentSubmitMapper.selectByExamDetailId(examDetail.getId());
            submits = submits.stream()
                    .filter(s -> s.getSubmitStatus() != null && s.getSubmitStatus() == 1)
                    .collect(Collectors.toList());
            if (submits.isEmpty()) {
                return new ArrayList<>();
            }
            List<Map<String, Object>> resultList = new ArrayList<>();
            calculateQuality(submits, examDetail, resultList, 0, "全体");
//            //按照班级分组
//            if(ObjectUtils.isEmpty(classIds)) {
//                classIds = submits.stream().map(StudentSubmit::getClassId).collect(Collectors.toList()).stream().distinct().collect(Collectors.toList());
//            }
//            List<ClassInfo> classInfos = classInfoMapper.selectByClassIds(classIds);
//            List<Long> finalClassIds = classIds;
//            Map<Long, List<StudentSubmit>> classMaps = submits.stream().filter(s-> finalClassIds.contains(s.getClassId())).collect(Collectors.groupingBy(StudentSubmit::getClassId));
//            classMaps.forEach((k, v)->{
//                Optional<ClassInfo> optionalValue = classInfos.stream().filter(c-> c.getClassId().equals(k)).findFirst();
//                String className = optionalValue.map(ClassInfo::getClassName).orElse("");
//                calculateQuality(v, examDetail, resultList, 1, className);
//            });
            return resultList;

        } catch (Exception e) {
            log.error("计算作业质量失败", e);
            throw new RuntimeException("计算作业质量失败: " + e.getMessage());
        }
    }

    private void calculateQuality(List<StudentSubmit> submits, ExamDetail examDetail, List<Map<String, Object>> resultList, int type, String name) {
        Map<String, Object> result = new HashMap<>();
        // 计算各项指标
        double avgScore = submits.stream()
                .mapToDouble(StudentSubmit::getScore)
                .average()
                .orElse(0.0);
        double difficulty = examDetail.getFullScore() > 0 ? avgScore / examDetail.getFullScore() : 0;

        double reliability = calculateSplitHalfReliability(submits);
        double discrimination = calculateDiscriminationIndex(submits, examDetail.getFullScore());

        result.put("fullScore", examDetail.getFullScore());
        result.put("submitCount", submits.size());
        result.put("avgScore", CommonUtils.formatNumber(avgScore));
        result.put("difficulty", CommonUtils.formatNumber(difficulty));
        result.put("reliability", CommonUtils.formatNumber(reliability));
        result.put("discrimination", CommonUtils.formatNumber(discrimination));

        // 评价结果
        List<Map<String, Object>> evaluations = new ArrayList<>();

        // 难度评价
        Map<String, Object> difficultyMap = new HashMap<>();
        difficultyMap.put("indicator", "难度");
        String difficultyDesc = "";
        if (difficulty <= 0.2) {
            difficultyDesc = "试题困难";
        }  else if (difficulty > 0.2 && difficulty <= 0.4) {
            difficultyDesc = "试题较难";
        } else if (difficulty > 0.4 && difficulty <= 0.6) {
            difficultyDesc = "试题一般";
        } else if (difficulty > 0.6 && difficulty <= 0.8) {
            difficultyDesc = "试题较易";
        } else {
            difficultyDesc = "试题容易";
        }
        difficultyMap.put("paperEvaluation", difficultyDesc);
        difficultyMap.put("questionEvaluation", calculateQuestionDifficultyDistribution(submits));
        evaluations.add(difficultyMap);

        // 信度评价
        Map<String, Object> reliabilityMap = new HashMap<>();
        reliabilityMap.put("indicator", "信度");
        String reliabilityDesc = "";
        if (reliability < 0.7) {
            reliabilityDesc = "信度较低(<0.7)，不宜使用";
        } else if (reliability < 0.85) {
            reliabilityDesc = "信度良好(0.7~0.85)，可用于团体比较";
        } else {
            reliabilityDesc = "信度优秀(>0.85)，可用于个体比较";
        }
        reliabilityMap.put("paperEvaluation", reliabilityDesc);
        reliabilityMap.put("questionEvaluation", "");  // 题目信度不适用
        evaluations.add(reliabilityMap);

        // 区分度评价
        Map<String, Object> discriminationMap = new HashMap<>();
        discriminationMap.put("indicator", "区分度");
        String discriminationDesc = "";
        if (discrimination < 0.2) {
            discriminationDesc = "区分度差(<0.2)，建议淘汰";
        } else if (discrimination < 0.3) {
            discriminationDesc = "区分度不太好(0.2~0.29)，需要修改";
        } else if (discrimination < 0.4) {
            discriminationDesc = "区分度较好(0.3~0.39)";
        } else {
            discriminationDesc = "区分度很好(>0.4)";
        }
        discriminationMap.put("paperEvaluation", discriminationDesc);
        discriminationMap.put("questionEvaluation", calculateQuestionDiscriminationDistribution(submits));
        evaluations.add(discriminationMap);

        result.put("evaluations", evaluations);
        resultList.add(result);
    }

    public List<Map<String, Object>> calculateGradeQuestionScoreRates(Long examId, List<Long> classIds) {
        try {
            // 获取考试详情
            ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
            if (examDetail == null) {
                throw new RuntimeException("未找到考试详情");
            }
            // 获取所有题目信息
            List<QuestionInfo> questions = questionInfoMapper.selectByExamDetailId(examDetail.getId());
            Map<Long, QuestionInfo> questionMap = questions.stream()
                    .collect(Collectors.toMap(QuestionInfo::getQuestionId, q -> q));
            // 获取所有学生提交记录
            List<StudentSubmit> examSubmits = studentSubmitMapper.selectByExamDetailId(examDetail.getId())
                    .stream()
                    .filter(s -> s.getSubmitStatus() == 1)
                    .collect(Collectors.toList());
            // 如果指定了班级，获取班级数据
            List<Map<String, Object>> result = new ArrayList<>();
            // 计算全部数据
            Map<String, Object> totalData = new HashMap<>();
            totalData.put("type", "0");
            totalData.put("name", "全体");
            totalData.put("questionList", calculateQuestionStats(examSubmits, questions, questionMap));
            result.add(totalData);
            //按照班级分组
            if(ObjectUtils.isEmpty(classIds)) {
                classIds = examSubmits.stream().map(StudentSubmit::getClassId).collect(Collectors.toList()).stream().distinct().collect(Collectors.toList());
            }
            List<ClassInfo> classInfos = classInfoMapper.selectByClassIds(classIds);
            List<Long> finalClassIds = classIds;
            Map<Long, List<StudentSubmit>> classMaps = examSubmits.stream().filter(s-> finalClassIds.contains(s.getClassId())).collect(Collectors.groupingBy(StudentSubmit::getClassId));
            // 如果有班级数据，计算班级数据
            classMaps.forEach((k, v) ->{
                Optional<ClassInfo> optionalValue = classInfos.stream().filter(c-> c.getClassId().equals(k)).findFirst();
                String className = optionalValue.map(ClassInfo::getClassName).orElse("");
                if (v != null) {
                    Map<String, Object> classData = new HashMap<>();
                    classData.put("type", "1");
                    classData.put("name", className);
                    classData.put("questionList", calculateQuestionStats(v, questions, questionMap));
                    result.add(classData);
                }
            });
            return result;
        } catch (Exception e) {
            log.error("计算试题得分率失败", e);
            throw new RuntimeException("计算试题得分率失败: " + e.getMessage());
        }
    }

    public List<Map<String, Object>> calculateKnowledgeScoreRates(Long examId, Long classId) {
        try {
            // 1. 获取考试详情
            ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
            if (examDetail == null) {
                throw new RuntimeException("未找到考试详情");
            }

            // 2. 获取题目得分情况
            List<Map<String, Object>> questionStats;
            if (!ObjectUtils.isEmpty(classId)) {
                ClassInfo classInfo = classInfoMapper.selectByClassId(classId, examDetail.getId());
                if (classInfo == null) {
                    throw new RuntimeException("未找到班级详情");
                }
                questionStats = questionScoreMapper.selectQuestionScoreByExamDetailIdAndClassDetailId(examDetail.getId(), classId);
            } else {
                questionStats = questionScoreMapper.selectQuestionScoreByExamDetail(examDetail.getId());
            }

            // 3. 获取题目的知识点信息
            List<String> questionBankIds = questionStats.stream().distinct()
                    .map(q -> q.get("questionBankId").toString())
                    .collect(Collectors.toList());

            // 4. 获取知识点映射
           // Map<String, String> knowledgeMap = new HashMap<>();
            List<KnowledgeMap> knowledgeMaps = new ArrayList<>();
            ResponseEntity<Map> response = sendPost(questionBankIds);
            if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
                Map<String, Object> responseBody = response.getBody();
                if(ObjectUtils.isEmpty(responseBody.get("data"))){
                    return new ArrayList<>();
                }
                List<Map<String, Object>> questionDataList = (List<Map<String, Object>>) responseBody.get("data");
                for (Map<String, Object> questionData : questionDataList) {
                    List<Map<String, Object>> knowledgeList = (List<Map<String, Object>>) questionData.get("questionKnowledgeChapterRelList");
                    if (knowledgeList != null && !knowledgeList.isEmpty()) {
                        knowledgeList.forEach(stringObjectMap -> {
                            KnowledgeMap km = new KnowledgeMap();
                            km.setKnowledge(stringObjectMap.get("knowledgeName").toString());
                            km.setQuestionUuid(stringObjectMap.get("questionUuid").toString());
                            km.setQuestionParentUuid(stringObjectMap.get("questionParentUuid").toString());
                            knowledgeMaps.add(km);
                        });
                    }
                }
            }

            // 5. 按知识点分组计算得分率
            Map<String, List<Map<String, Object>>> knowledgeGroups = new HashMap<>();
            for (Map<String, Object> stat : questionStats) {
                String questionBankId = stat.get("questionBankId").toString();
                List<String> knowledges = knowledgeMaps.stream().filter(km-> km.getQuestionUuid().equals(questionBankId)).collect(Collectors.toList()).stream().map(KnowledgeMap::getKnowledge).collect(Collectors.toList());
                for(String knowledge : knowledges) {
                    knowledgeGroups.computeIfAbsent(knowledge, k -> new ArrayList<>()).add(stat);
                }
            }

            // 6. 计算每个知识点的统计数据
            List<Map<String, Object>> result = new ArrayList<>();
            for (Map.Entry<String, List<Map<String, Object>>> entry : knowledgeGroups.entrySet()) {
                String knowledge = entry.getKey();
                List<Map<String, Object>> questions = entry.getValue();

                // 计算该知识点的总得分和总分
                double totalScore = 0.0;  // 总得分
                double fullScore = 0.0;   // 总分
                for (Map<String, Object> question : questions) {
                    double score = Double.parseDouble(question.get("score").toString());  // 实际得分
                    double questionScore = Double.parseDouble(question.get("questionScore").toString());  // 题目满分

                    totalScore += score ;  // 累加总得分
                    fullScore += questionScore;  // 累加总分
                }

                // 计算得分率
                // 格式化题型和题号信息
                List<String> questionNums = new ArrayList<>();
                double scoreRate = fullScore > 0 ? (totalScore / fullScore) * 100 : 0.0;
                for (Map<String, Object> question : questions) {
                    String questionNum = "";
                    if(!ObjectUtils.isEmpty(question.get("questionAlias"))){
                        questionNum = question.get("questionTypeName").toString() +"-" + question.get("questionAlias").toString();
                        if (questionNums.contains(questionNum)) {
                            continue;
                        }
                    }else {
                        questionNum = question.get("questionTypeName").toString() +"-" + (int) question.get("questionNum") / 100000;
                        if (questionNums.contains(questionNum)) {
                            continue;
                        }
                    }
                    questionNums.add(questionNum);
                }
                Map<String, Object> knowledgeStat = new HashMap<>();
                knowledgeStat.put("knowledge", knowledge);
                knowledgeStat.put("scoreRate", String.format("%.1f", scoreRate));
                knowledgeStat.put("questionNums", questionNums);

                result.add(knowledgeStat);
            }

            return result;

        } catch (Exception e) {
            log.error("计算知识点得分率失败: {}", e.getMessage(), e);
            throw new RuntimeException("计算知识点得分率失败: " + e.getMessage());
        }
    }

    public List<Map<String, Object>> calculateGradeQuestionAnalysis(Long examId, List<Long> classIds) {
        try {
            // 获取考试详情
            ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
            if (examDetail == null) {
                throw new RuntimeException("未找到考试详情");
            }

            // 获取所有学生提交记录
            List<StudentSubmit> examSubmits = studentSubmitMapper.selectByExamDetailId(examDetail.getId())
                    .stream()
                    .filter(s -> s.getSubmitStatus() == 1)
                    .collect(Collectors.toList());
            // 获取所有题目信息
            List<QuestionInfo> questions = questionInfoMapper.selectByExamDetailId(examDetail.getId());
            // 按题号排序
            questions.sort(Comparator.comparing(QuestionInfo::getQuestionNum));
            List<Map<String, Object>> result = new ArrayList<>();
            // 计算全部数据
            Map<String, Object> totalData = new HashMap<>();
            totalData.put("type", "0");
            totalData.put("name", "全体");
            totalData.put("questionList", calculateQuestionAnalysisStats(examSubmits, questions));
            result.add(totalData);
            if(ObjectUtils.isEmpty(classIds)) {
                classIds = examSubmits.stream().map(StudentSubmit::getClassId).collect(Collectors.toList()).stream().distinct().collect(Collectors.toList());
            }
            List<ClassInfo> classInfos = classInfoMapper.selectByClassIds(classIds);
            List<Long> finalClassIds = classIds;
            Map<Long, List<StudentSubmit>> classMaps = examSubmits.stream().filter(s-> finalClassIds.contains(s.getClassId())).collect(Collectors.groupingBy(StudentSubmit::getClassId));
            // 如果有班级数据，计算班级数据
            classMaps.forEach((k, v)->{
                if (v != null) {
                    Map<String, Object> classData = new HashMap<>();
                    classData.put("type", "1");
                    ClassInfo classInfo = classInfos.stream().filter(c-> c.getClassId().equals(k)).findFirst().orElse(null);
                    classData.put("name", classInfo != null ? classInfo.getClassName() : "未知班级");
                    classData.put("questionList", calculateQuestionAnalysisStats(v, questions));
                    result.add(classData);
                }
            });
            return result;
        } catch (Exception e) {
            log.error("计算小题分析失败", e);
            throw new RuntimeException("计算小题分析失败: " + e.getMessage());
        }
    }

    public List<Map<String, Object>> calculateGradeObjectiveAnswerDistribution(Long examId, List<Long> classIds) {
        try {
            // 获取考试详情
            ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
            if (examDetail == null) {
                throw new RuntimeException("未找到考试详情");
            }

            // 获取所有客观题信息
            List<QuestionInfo> questions = questionInfoMapper.selectByExamDetailId(examDetail.getId())
                    .stream()
                    .filter(q -> q.getIsSubjectiveItem() == 0)
                    .sorted(Comparator.comparing(QuestionInfo::getQuestionNum))
                    .collect(Collectors.toList());

            // 获取学生提交记录
            List<StudentSubmit> submits = studentSubmitMapper.selectByExamDetailId(examDetail.getId());
            submits = submits.stream().filter(s-> s.getSubmitStatus() == 1).collect(Collectors.toList());
            if(!ObjectUtils.isEmpty(classIds)){
                submits = submits.stream().filter(s-> classIds.contains(s.getClassId())).collect(Collectors.toList());
            }
            if(submits.isEmpty()){
                throw new RuntimeException("未找到提交信息");
            }
            // 批量获取所有题目的得分记录
            List<Long> submitIds = submits.stream()
                    .map(StudentSubmit::getId)
                    .collect(Collectors.toList());
            List<QuestionScore> allScores = questionScoreMapper.selectByStudentSubmitIds(submitIds);

            // 按题目ID分组
            Map<Long, List<QuestionScore>> scoresByQuestionId = allScores.stream()
                    .collect(Collectors.groupingBy(QuestionScore::getQuestionId));

            List<Map<String, Object>> result = new ArrayList<>();

            for (QuestionInfo question : questions) {
                Map<String, Object> distribution = new HashMap<>();
                List<QuestionScore> scores = scoresByQuestionId.getOrDefault(question.getQuestionId(), new ArrayList<>());

                if (!scores.isEmpty()) {
                    // 计算平均分
                    double avgScore = scores.stream()
                            .mapToDouble(QuestionScore::getScore)
                            .average()
                            .orElse(0.0);

                    // 计算得分率
                    double scoreRate = avgScore / question.getQuestionScore() * 100;

                    // 计算满分率
                    long fullScoreCount = scores.stream()
                            .filter(s -> s.getScore() >= question.getQuestionScore())
                            .count();
                    double fullScoreRate = (double) fullScoreCount / scores.size() * 100;

                    // 计算零分率
                    long zeroScoreCount = scores.stream()
                            .filter(s -> s.getScore() == 0)
                            .count();
                    double zeroScoreRate = (double) zeroScoreCount / scores.size() * 100;
                    if(!ObjectUtils.isEmpty(question.getQuestionAlias())){
                        distribution.put("questionNum", question.getQuestionTypeName() + "-" + question.getQuestionAlias());
                    }else {
                        int bigQuestionNum = CalculateQuestionNumUtil.bigQuestionNum(question.getQuestionNum());
                        int smallQuestionNum = CalculateQuestionNumUtil.smallQuestionNum(question.getQuestionNum());
                        if (smallQuestionNum != 0) {
                            distribution.put("questionNum", bigQuestionNum + "-" + question.getQuestionTypeName() + "-" + smallQuestionNum);
                        } else {
                            distribution.put("questionNum", question.getQuestionTypeName() + "-" + bigQuestionNum);
                        }
                    }
                    distribution.put("answer", question.getQuestionAnswer());
                    distribution.put("score", question.getQuestionScore());
                    distribution.put("avgScore", String.format("%.2f", avgScore));
                    distribution.put("scoreRate", String.format("%.2f", scoreRate));
                    distribution.put("fullScoreRate", String.format("%.2f", fullScoreRate));
                    distribution.put("zeroScoreRate", String.format("%.2f", zeroScoreRate));
                    distribution.put("studentAnswer", getObjectiveAnswerDistribution(scores));

                    result.add(distribution);
                }
            }

            return result;
        } catch (Exception e) {
            log.error("计算客观题作答分布失败", e);
            throw new RuntimeException("计算客观题作答分布失败: " + e.getMessage());
        }
    }


    public List<Map<String, Object>> calculateGradeSubjectiveAnswerDistribution(Long examId, List<Long> classIds) {
        // 同样的优化方式应用到主观题分布计算
        try {
            ExamDetail examDetail = examDetailMapper.selectByExamId(examId);
            if (examDetail == null) {
                throw new RuntimeException("未找到考试详情");
            }

            List<QuestionInfo> questions = questionInfoMapper.selectByExamDetailId(examDetail.getId())
                    .stream()
                    .filter(q -> q.getIsSubjectiveItem() == 1)
                    .sorted(Comparator.comparing(QuestionInfo::getQuestionNum))
                    .collect(Collectors.toList());

            // 获取学生提交记录
            List<StudentSubmit> submits = studentSubmitMapper.selectByExamDetailId(examDetail.getId());
            submits = submits.stream().filter(s-> s.getSubmitStatus() == 1).collect(Collectors.toList());
            if(!ObjectUtils.isEmpty(classIds)){
                submits = submits.stream().filter(s-> classIds.contains(s.getClassId())).collect(Collectors.toList());
            }
            if(submits.isEmpty()){
                throw new RuntimeException("未找到提交信息");
            }
            // 批量获取所有题目的得分记录
            List<Long> submitIds = submits.stream()
                    .map(StudentSubmit::getId)
                    .collect(Collectors.toList());
            List<QuestionScore> allScores = questionScoreMapper.selectByStudentSubmitIds(submitIds);

            // 按题目ID分组
            Map<Long, List<QuestionScore>> scoresByQuestionId = allScores.stream()
                    .collect(Collectors.groupingBy(QuestionScore::getQuestionId));

            List<Map<String, Object>> result = new ArrayList<>();

            for (QuestionInfo question : questions) {
                Map<String, Object> distribution = new HashMap<>();
                List<QuestionScore> scores = scoresByQuestionId.getOrDefault(question.getQuestionId(), new ArrayList<>());

                if (!scores.isEmpty()) {
                    // 计算平均分
                    double avgScore = scores.stream()
                            .mapToDouble(QuestionScore::getScore)
                            .average()
                            .orElse(0.0);

                    // 计算得分率
                    double scoreRate = avgScore / question.getQuestionScore() * 100;

                    // 计算满分率
                    long fullScoreCount = scores.stream()
                            .filter(s -> s.getScore() >= question.getQuestionScore())
                            .count();
                    double fullScoreRate = (double) fullScoreCount / scores.size() * 100;

                    // 计算零分率
                    long zeroScoreCount = scores.stream()
                            .filter(s -> s.getScore() == 0)
                            .count();
                    double zeroScoreRate = (double) zeroScoreCount / scores.size() * 100;
                    if(!ObjectUtils.isEmpty(question.getQuestionAlias())){
                        distribution.put("questionNum", question.getQuestionTypeName() + "-" + question.getQuestionAlias());
                    }else {
                        int bigQuestionNum = CalculateQuestionNumUtil.bigQuestionNum(question.getQuestionNum());
                        int smallQuestionNum = CalculateQuestionNumUtil.smallQuestionNum(question.getQuestionNum());
                        if (smallQuestionNum != 0) {
                            distribution.put("questionNum", bigQuestionNum + "-" + question.getQuestionTypeName() + "-" + smallQuestionNum);
                        } else {
                            distribution.put("questionNum", question.getQuestionTypeName() + "-" + bigQuestionNum);
                        }
                    }
                    distribution.put("answer", question.getQuestionAnswer()!= null? question.getQuestionAnswer() : "-");
                    distribution.put("score", question.getQuestionScore());
                    distribution.put("avgScore", String.format("%.2f", avgScore));
                    distribution.put("scoreRate", String.format("%.2f", scoreRate));
                    distribution.put("fullScoreRate", String.format("%.2f", fullScoreRate));
                    distribution.put("zeroScoreRate", String.format("%.2f", zeroScoreRate));
                    distribution.put("studentAnswer", getSubjectiveScoreDistribution(scores, question.getQuestionScore()));

                    result.add(distribution);
                }
            }

            return result;
        } catch (Exception e) {
            log.error("计算主观题作答分布失败", e);
            throw new RuntimeException("计算主观题作答分布失败: " + e.getMessage());
        }
    }

    //客观题排序
    public static class QuestionKeyComparator implements Comparator<String> {
        // 正则表达式模式，新增纯数字匹配
        private static final Pattern PATTERN0 = Pattern.compile("^(\\d+)$"); // 纯数字题号
        private static final Pattern PATTERN1 = Pattern.compile("^(\\d+)-(.*?)-(\\d+)$"); // 格式：数字-题型-数字
        private static final Pattern PATTERN2 = Pattern.compile("^(.*?)-(\\d+)$"); // 格式：题型-数字
        private static final Pattern PATTERN3 = Pattern.compile("^(\\d+)(.*?)-(\\d+)$"); // 格式：数字题型-数字

        @Override
        public int compare(String key1, String key2) {
            QuestionInfo info1 = parseKey(key1);
            QuestionInfo info2 = parseKey(key2);

            // 先比较题型
            int typeCompare = compareType(info1.type, info2.type);
            if (typeCompare != 0) {
                return typeCompare;
            }

            // 题型相同，比较大题号
            int majorNumCompare = Integer.compare(info1.majorNumber, info2.majorNumber);
            if (majorNumCompare != 0) {
                return majorNumCompare;
            }

            // 大题号相同，比较小题号
            return Integer.compare(info1.minorNumber, info2.minorNumber);
        }

        private int compareType(String type1, String type2) {
            // 尝试将题型解析为数字进行比较
            try {
                int num1 = Integer.parseInt(type1);
                int num2 = Integer.parseInt(type2);
                return Integer.compare(num1, num2);
            } catch (NumberFormatException e) {
                // 若无法解析为数字，则按字符串比较
                return type1.compareTo(type2);
            }
        }

        private QuestionInfo parseKey(String key) {
            // 新增纯数字匹配
            Matcher matcher0 = PATTERN0.matcher(key);
            if (matcher0.matches()) {
                int majorNumber = Integer.parseInt(matcher0.group(1));
                return new QuestionInfo("", majorNumber, 0);
            }

            // 尝试匹配格式1：数字-题型-数字
            Matcher matcher1 = PATTERN1.matcher(key);
            if (matcher1.matches()) {
                int majorNumber = Integer.parseInt(matcher1.group(1));
                String type = matcher1.group(2);
                int minorNumber = Integer.parseInt(matcher1.group(3));
                return new QuestionInfo(type, majorNumber, minorNumber);
            }

            // 尝试匹配格式2：题型-数字
            Matcher matcher2 = PATTERN2.matcher(key);
            if (matcher2.matches()) {
                String type = matcher2.group(1);
                int majorNumber = Integer.parseInt(matcher2.group(2));
                return new QuestionInfo(type, majorNumber, 0);
            }

            // 尝试匹配格式3：数字题型-数字
            Matcher matcher3 = PATTERN3.matcher(key);
            if (matcher3.matches()) {
                int majorNumber = Integer.parseInt(matcher3.group(1));
                String type = matcher3.group(2);
                int minorNumber = Integer.parseInt(matcher3.group(3));
                return new QuestionInfo(type, majorNumber, minorNumber);
            }

            // 无法匹配任何格式时的默认处理
            return new QuestionInfo(key, 0, 0);
        }

        static class QuestionInfo {
            String type; // 题型
            int majorNumber; // 大题号
            int minorNumber; // 小题号

            public QuestionInfo(String type, int majorNumber, int minorNumber) {
                this.type = type;
                this.majorNumber = majorNumber;
                this.minorNumber = minorNumber;
            }
        }
    }
    //主观题排序
    public static class SubQuestionKeyComparator implements Comparator<String> {
        private static final Pattern PATTERN = Pattern.compile("^(?:(\\d+)-)?(.*?)-(\\d+)$");

        @Override
        public int compare(String key1, String key2) {
            QuestionInfo info1 = parseKey(key1);
            QuestionInfo info2 = parseKey(key2);

            int majorNumCompare = Integer.compare(info1.majorNumber, info2.majorNumber);
            if (majorNumCompare != 0) {
                return majorNumCompare;
            }

            Collator collator = Collator.getInstance(Locale.CHINA);
            int typeCompare = collator.compare(info1.type, info2.type);
            if (typeCompare != 0) {
                return typeCompare;
            }

            return Integer.compare(info1.minorNumber, info2.minorNumber);
        }

        private QuestionInfo parseKey(String key) {
            Matcher matcher = PATTERN.matcher(key);
            if (matcher.matches()) {
                String majorNumStr = matcher.group(1);
                int majorNumber = majorNumStr != null ? Integer.parseInt(majorNumStr) : 0;
                String type = matcher.group(2);
                int minorNumber = Integer.parseInt(matcher.group(3));
                return new QuestionInfo(majorNumber, type, minorNumber);
            }
            return new QuestionInfo(0, key, 0);
        }

        static class QuestionInfo {
            int majorNumber;
            String type;
            int minorNumber;

            public QuestionInfo(int majorNumber, String type, int minorNumber) {
                this.majorNumber = majorNumber;
                this.type = type;
                this.minorNumber = minorNumber;
            }
        }
    }
}